From 18247ebfb83ab5d0d00959c0e0e162613688325c Mon Sep 17 00:00:00 2001 From: Lukas Date: Sat, 29 May 2021 15:32:28 +0200 Subject: [PATCH] rendering: introduce new hud system --- .../minosoft/gui/rendering/hud/HUDRenderer.kt | 3 +- .../rendering/hud/atlas/HUDAtlasElement.kt | 9 +++ .../position/HUDElementPositionAnchors.kt | 27 ++++++++ .../nodes/position/HUDElementPositionUnits.kt | 37 +++++++++++ .../hud/nodes/position/HUDElementVec2.kt | 33 ++++++++++ .../hud/nodes/primitive/HUDElement.kt | 42 +++++++++++++ .../nodes/primitive/HUDElementSerializer.kt | 35 +++++++++++ .../hud/nodes/primitive/HUDImageElement.kt | 62 +++++++++++++++++++ .../minosoft/gui/rendering/util/VecUtil.kt | 16 +++++ .../minosoft/util/json/JSONSerializer.kt | 1 + 10 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementPositionAnchors.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementPositionUnits.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementVec2.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDElement.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDElementSerializer.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDImageElement.kt diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt index 562ab27e2..f9b54670b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt @@ -21,6 +21,7 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.RendererBuilder import de.bixilon.minosoft.gui.rendering.hud.atlas.HUDAtlasElement +import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.HUDElement import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.HUDElement import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent import de.bixilon.minosoft.gui.rendering.shader.Shader @@ -68,7 +69,7 @@ class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow } private fun registerElements() { - for ((resourceLocation, hudElement) in Minosoft.getConfig().config.game.elements.entries) { + for ((resourceLocation, hudElement) in Minosoft.getConfig().config.game.elements.entries.entries) { hudElements[resourceLocation] = hudElement enabledHUDElements[resourceLocation] = hudElement hudElement.init(this) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/atlas/HUDAtlasElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/atlas/HUDAtlasElement.kt index 5ac03bd51..a453406a5 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/atlas/HUDAtlasElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/atlas/HUDAtlasElement.kt @@ -32,6 +32,15 @@ data class HUDAtlasElement( override val size: Vec2i get() = binding.size + val uvs: Array get() { + return arrayOf( + Vec2(uvStart.x, uvStart.y), + Vec2(uvStart.x, uvEnd.y), + Vec2(uvEnd.x, uvStart.y), + Vec2(uvEnd.x, uvEnd.y), + ) + } + fun postInit() { uvStart = (Vec2(binding.start) + RenderConstants.PIXEL_UV_PIXEL_ADD) * texture.arraySinglePixelFactor uvEnd = Vec2(binding.end) * texture.arraySinglePixelFactor diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementPositionAnchors.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementPositionAnchors.kt new file mode 100644 index 000000000..c12595820 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementPositionAnchors.kt @@ -0,0 +1,27 @@ +package de.bixilon.minosoft.gui.rendering.hud.nodes.position + +import de.bixilon.minosoft.data.mappings.ResourceLocation +import glm_.vec2.Vec2i + +enum class HUDElementPositionAnchors(val resourceLocation: ResourceLocation, val quadTransform: (Vec2i, Vec2i) -> Array) { + CENTER(ResourceLocation("minosoft:center"), { position, size -> + arrayOf( + Vec2i(position.x + size.x * 0.5f, position.y + size.y * 0.5f), + Vec2i(position.x + size.x * 0.5f, position.y - size.y * 0.5f), + Vec2i(position.x - size.x * 0.5f, position.y + size.y * 0.5f), + Vec2i(position.x - size.x * 0.5f, position.y - size.y * 0.5f), + ) + }) + ; + companion object { + val HUD_ELEMENT_POSITION_ATTACHMENT_OPTIONS = values() + + val HUD_ELEMENT_POSITION_ATTACHMENTS_MAPPING = run { + val result = mutableMapOf() + for (hudPositionAttachmentOption in HUD_ELEMENT_POSITION_ATTACHMENT_OPTIONS) { + result[hudPositionAttachmentOption.resourceLocation] = hudPositionAttachmentOption + } + result + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementPositionUnits.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementPositionUnits.kt new file mode 100644 index 000000000..dfb39b403 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementPositionUnits.kt @@ -0,0 +1,37 @@ +package de.bixilon.minosoft.gui.rendering.hud.nodes.position + +import de.bixilon.minosoft.Minosoft +import de.bixilon.minosoft.data.Axes +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.util.VecUtil.get + +enum class HUDElementPositionUnits(val resourceLocation: ResourceLocation, val realPositionConversion: (Float, HUDRenderer, Axes) -> Float) { + PIXELS(ResourceLocation("minosoft:pixel"), { it, _, _ -> + it + }), + SCALED_PIXELS(ResourceLocation("minosoft:scaled_pixel"), { it, _, _ -> + it * Minosoft.getConfig().config.game.hud.scale + }), + UNIT(ResourceLocation("minosoft:unit"), { it, hudRenderer, axis -> + it * hudRenderer.renderWindow.screenDimensions[axis] / TOTAL_UNITS + }), + SCALED_UNIT(ResourceLocation("minosoft:scaled_unit"), { it, hudRenderer, axis -> + it * hudRenderer.renderWindow.screenDimensions[axis] / TOTAL_UNITS * Minosoft.getConfig().config.game.hud.scale + }) + ; + + companion object { + val HUD_ELEMENT_POSITION_UNITS = values() + + val HUD_ELEMENT_POSITION_MAP = run { + val result = mutableMapOf() + for (unit in HUD_ELEMENT_POSITION_UNITS) { + result[unit.resourceLocation] = unit + } + result + } + + const val TOTAL_UNITS = 100f + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementVec2.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementVec2.kt new file mode 100644 index 000000000..df088dfe2 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/position/HUDElementVec2.kt @@ -0,0 +1,33 @@ +package de.bixilon.minosoft.gui.rendering.hud.nodes.position + +import de.bixilon.minosoft.data.Axes +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer +import glm_.vec2.Vec2i + +class HUDElementVec2( + val x: Float, + val xUnit: HUDElementPositionUnits, + val y: Float, + val yUnit: HUDElementPositionUnits, +) { + fun getRealVector(hudRenderer: HUDRenderer): Vec2i { + return Vec2i( + xUnit.realPositionConversion.invoke(x, hudRenderer, Axes.X), + yUnit.realPositionConversion.invoke(y, hudRenderer, Axes.Y) + ) + } + + companion object { + fun deserialize(data: Any?): HUDElementVec2? { + if (data !is Map<*, *>) { + return null + } + val x = (data["x"] as Double).toFloat() + val xUnit = HUDElementPositionUnits.HUD_ELEMENT_POSITION_MAP[ResourceLocation(data["x_unit"].toString())] ?: HUDElementPositionUnits.PIXELS + val y = (data["x"] as Double).toFloat() + val yUnit = HUDElementPositionUnits.HUD_ELEMENT_POSITION_MAP[ResourceLocation(data["y_unit"].toString())] ?: HUDElementPositionUnits.PIXELS + return HUDElementVec2(x, xUnit, y, yUnit) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDElement.kt new file mode 100644 index 000000000..1fe369f29 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDElement.kt @@ -0,0 +1,42 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * 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.nodes.primitive + +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.text.RGBColor +import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.hud.nodes.position.HUDElementPositionAnchors +import de.bixilon.minosoft.gui.rendering.hud.nodes.position.HUDElementVec2 +import glm_.mat4x4.Mat4 + +abstract class HUDElement( + val position: HUDElementVec2, + val positionAnchor: HUDElementPositionAnchors, + val content: ResourceLocation, + val size: HUDElementVec2, + val realZ: Float, + val tint: RGBColor, +) { + lateinit var hudRenderer: HUDRenderer + + open fun init(hudRenderer: HUDRenderer) { + this.hudRenderer = hudRenderer + } + + open fun postInit() {} + + open fun draw() {} + + open fun prepare(matrix: Mat4) {} +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDElementSerializer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDElementSerializer.kt new file mode 100644 index 000000000..c3ad827a2 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDElementSerializer.kt @@ -0,0 +1,35 @@ +package de.bixilon.minosoft.gui.rendering.hud.nodes.primitive + +import com.squareup.moshi.FromJson +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.gui.rendering.hud.nodes.position.HUDElementPositionAnchors +import de.bixilon.minosoft.gui.rendering.hud.nodes.position.HUDElementVec2 +import de.bixilon.minosoft.util.json.RGBColorSerializer + +object HUDElementSerializer { + @FromJson + fun fromJson(json: Map): HUDElement? { + val position = HUDElementVec2.deserialize(json["position"]) + val positionAnchor = HUDElementPositionAnchors.HUD_ELEMENT_POSITION_ATTACHMENTS_MAPPING[ResourceLocation((json["position"] as Map<*,*>)["location"].toString())]!! + val size = HUDElementVec2.deserialize(json["size"]) + return HUD_ELEMENT_TYPES[ResourceLocation(json["type"].toString())]?.constructors?.first()?.call( + position, + positionAnchor, + ResourceLocation(json["content"].toString()), + size, + (json["real_z"] as Double).toFloat(), + json["tint"]?.let{ RGBColorSerializer.fromJsonValue(it) }, + ) + } + + @ToJson + fun toJson(jsonWriter: JsonWriter, hudElement: HUDElement?) { + } + + private val HUD_ELEMENT_TYPES = mutableMapOf( + ResourceLocation("minosoft:image_element") to HUDImageElement::class, + // modding here! + ) +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDImageElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDImageElement.kt new file mode 100644 index 000000000..8db4b0c60 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/primitive/HUDImageElement.kt @@ -0,0 +1,62 @@ +package de.bixilon.minosoft.gui.rendering.hud.nodes.primitive + +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.text.ChatColors +import de.bixilon.minosoft.data.text.RGBColor +import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.hud.atlas.HUDAtlasElement +import de.bixilon.minosoft.gui.rendering.hud.nodes.position.HUDElementPositionAnchors +import de.bixilon.minosoft.gui.rendering.hud.nodes.position.HUDElementVec2 +import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh +import de.bixilon.minosoft.gui.rendering.util.mesh.SimpleTextureMesh +import glm_.mat4x4.Mat4 +import glm_.vec2.Vec2 +import glm_.vec3.Vec3 +import glm_.vec4.Vec4 +import glm_.vec4.swizzle.xy + +class HUDImageElement( + position: HUDElementVec2, + positionAnchor: HUDElementPositionAnchors, + content: ResourceLocation, + size: HUDElementVec2, + realZ: Float, + tint: RGBColor = ChatColors.WHITE, +) : HUDElement(position, positionAnchor, content, size, realZ, tint) { + + private var mesh = SimpleTextureMesh() + + private lateinit var hudAtlasElement: HUDAtlasElement + + override fun init(hudRenderer: HUDRenderer) { + super.init(hudRenderer) + hudAtlasElement = hudRenderer.hudAtlasElements[content]!! + } + + override fun draw() { + mesh.draw() + } + + override fun prepare(matrix: Mat4) { + super.prepare(matrix) + if (mesh.state == Mesh.MeshStates.LOADED) { + mesh.unload() + mesh = SimpleTextureMesh() + } + val realPosition = position.getRealVector(hudRenderer) + val realSize = size.getRealVector(hudRenderer) + fun addVertex(position: Vec2, textureUV: Vec2) { + mesh.addVertex(Vec3( + position.x, + position.y, + realZ, + ), hudAtlasElement.texture, textureUV, tint) + } + val positions = positionAnchor.quadTransform.invoke(realPosition, realSize) + val uvs = hudAtlasElement.uvs + for (position in arrayOf(0, 1, 2, 1, 3, 2)) { + addVertex((matrix * Vec4(positions[position], 1f, 1f)).xy, uvs[position]) + } + mesh.load() + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt index c7eda2062..9c5dcf057 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt @@ -514,4 +514,20 @@ object VecUtil { z = 0.0 } } + + operator fun Vec2i.get(axis: Axes): Int { + return when (axis) { + Axes.X -> this.x + Axes.Y -> this.y + Axes.Z -> throw java.lang.IllegalArgumentException("Z does not exist") + } + } + + operator fun Vec2.get(axis: Axes): Float { + return when (axis) { + Axes.X -> this.x + Axes.Y -> this.y + Axes.Z -> throw java.lang.IllegalArgumentException("Z does not exist") + } + } } diff --git a/src/main/java/de/bixilon/minosoft/util/json/JSONSerializer.kt b/src/main/java/de/bixilon/minosoft/util/json/JSONSerializer.kt index 56a4e7567..f1007d44d 100644 --- a/src/main/java/de/bixilon/minosoft/util/json/JSONSerializer.kt +++ b/src/main/java/de/bixilon/minosoft/util/json/JSONSerializer.kt @@ -18,6 +18,7 @@ import com.squareup.moshi.Moshi import com.squareup.moshi.Types import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import de.bixilon.minosoft.config.config.Config +import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.HUDElementSerializer import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.HUDElementSerializer import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties