rendering: introduce new hud system

This commit is contained in:
Lukas 2021-05-29 15:32:28 +02:00
parent 8eee74df5d
commit 66a726423e
34 changed files with 261 additions and 1457 deletions

View File

@ -14,8 +14,8 @@
package de.bixilon.minosoft.config.config.game.elements
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.gui.rendering.hud.HUDElementProperties
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.HUDElement
data class ElementsGameConfig(
val entries: MutableMap<ResourceLocation, HUDElementProperties> = mutableMapOf(),
val entries: MutableMap<ResourceLocation, HUDElement> = mutableMapOf(),
)

View File

@ -17,12 +17,7 @@ import com.google.gson.JsonElement
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.locale.minecraft.Translator
import de.bixilon.minosoft.data.text.RGBColor.Companion.asColor
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.font.text.TextGetProperties
import de.bixilon.minosoft.gui.rendering.font.text.TextSetProperties
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.LabelNode
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import glm_.vec2.Vec2i
import javafx.collections.ObservableList
import javafx.scene.Node
import java.text.CharacterIterator
@ -178,12 +173,6 @@ class BaseComponent : ChatComponent {
return nodes
}
override fun prepareRender(startPosition: Vec2i, offset: Vec2i, renderWindow: RenderWindow, textElement: LabelNode, z: Int, setProperties: TextSetProperties, getProperties: TextGetProperties) {
for (part in parts) {
part.prepareRender(startPosition, offset, renderWindow, textElement, z, setProperties, getProperties)
}
}
override fun applyDefaultColor(color: RGBColor) {
for (part in parts) {
part.applyDefaultColor(color)

View File

@ -17,11 +17,6 @@ import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.google.gson.JsonPrimitive
import de.bixilon.minosoft.data.locale.minecraft.Translator
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.font.text.TextGetProperties
import de.bixilon.minosoft.gui.rendering.font.text.TextSetProperties
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.LabelNode
import glm_.vec2.Vec2i
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.scene.Node
@ -59,11 +54,6 @@ interface ChatComponent {
fun applyDefaultColor(color: RGBColor)
/**
* Prepares the chat component for rendering (used in opengl)
*/
fun prepareRender(startPosition: Vec2i, offset: Vec2i, renderWindow: RenderWindow, textElement: LabelNode, z: Int, setProperties: TextSetProperties, getProperties: TextGetProperties)
companion object {
@JvmOverloads

View File

@ -13,17 +13,8 @@
package de.bixilon.minosoft.data.text
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.font.text.TextGetProperties
import de.bixilon.minosoft.gui.rendering.font.text.TextSetProperties
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.ImageNode
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.LabelNode
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeSizing
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.Util
import glm_.vec2.Vec2i
import javafx.animation.Animation
import javafx.animation.KeyFrame
import javafx.animation.Timeline
@ -161,52 +152,4 @@ open class TextComponent(
nodes.add(text)
return nodes
}
override fun prepareRender(startPosition: Vec2i, offset: Vec2i, renderWindow: RenderWindow, textElement: LabelNode, z: Int, setProperties: TextSetProperties, getProperties: TextGetProperties) {
val color = this.color ?: ProtocolDefinition.DEFAULT_COLOR
// bring chars in right order and reverse them if right bound
val charArray = this.message.toCharArray().toList()
fun checkGetSize(charEnd: Vec2i) {
if (charEnd.x > getProperties.size.x) {
getProperties.size.x = charEnd.x
}
if (charEnd.y > getProperties.size.y) {
getProperties.size.y = charEnd.y
}
}
fun pushNewLine() {
offset.x = 0
offset.y += Font.CHAR_HEIGHT + RenderConstants.TEXT_LINE_PADDING
checkGetSize(Vec2i(0, 0))
}
// add all chars
for (char in charArray) {
if (ProtocolDefinition.LINE_BREAK_CHARS.contains(char)) {
pushNewLine()
continue
}
val fontChar = renderWindow.font.getChar(char)
val charSize = fontChar.size
var charStart = Vec2i(offset)
var charEnd = charStart + charSize
if (charEnd.x >= setProperties.hardWrap) {
pushNewLine()
charStart = Vec2i(offset)
charEnd = charStart + charSize
}
textElement.addChild(charStart + startPosition, ImageNode(renderWindow, NodeSizing(minSize = charSize), fontChar, 1, color))
offset.x += charSize.x + Font.SPACE_BETWEEN_CHARS
checkGetSize(charEnd)
}
}
}

View File

@ -1,23 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud
import de.bixilon.minosoft.gui.rendering.util.mesh.SimpleTextureMesh
class HUDMesh : SimpleTextureMesh() {
fun addCacheMesh(cacheMesh: HUDCacheMesh) {
data.addAll(cacheMesh.cache)
}
}

View File

@ -1,23 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud
import de.bixilon.minosoft.data.mappings.CompanionResourceLocation
import de.bixilon.minosoft.gui.rendering.hud.nodes.HUDElement
interface HUDRenderBuilder<T : HUDElement> : CompanionResourceLocation {
val DEFAULT_PROPERTIES: HUDElementProperties
fun build(hudRenderer: HUDRenderer): T
}

View File

@ -21,120 +21,57 @@ 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.elements.other.BreakProgressHUDElement
import de.bixilon.minosoft.gui.rendering.hud.elements.other.CrosshairHUDElement
import de.bixilon.minosoft.gui.rendering.hud.nodes.HUDElement
import de.bixilon.minosoft.gui.rendering.hud.nodes.chat.ChatBoxHUDElement
import de.bixilon.minosoft.gui.rendering.hud.nodes.debug.HUDSystemDebugNode
import de.bixilon.minosoft.gui.rendering.hud.nodes.debug.HUDWorldDebugNode
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.HUDElement
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
import de.bixilon.minosoft.gui.rendering.shader.Shader
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.MMath
import de.bixilon.minosoft.util.json.ResourceLocationJsonMap.toResourceLocationMap
import glm_.glm
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2i
class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow) : Renderer {
private val hudElements: MutableMap<ResourceLocation, Pair<HUDElementProperties, HUDElement>> = mutableMapOf()
private val enabledHUDElement: MutableMap<ResourceLocation, Pair<HUDElementProperties, HUDElement>> = mutableMapOf()
private val hudElements: MutableMap<ResourceLocation, HUDElement> = mutableMapOf()
private val enabledHUDElements: MutableMap<ResourceLocation, HUDElement> = mutableMapOf()
private val hudShader = Shader(
resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "hud"),
)
lateinit var hudAtlasElements: Map<ResourceLocation, HUDAtlasElement>
var orthographicMatrix: Mat4 = Mat4()
private set
var currentHUDMesh: HUDMesh = HUDMesh()
private var hudEnabled = true
private var forcePrepare = true
override fun init() {
hudShader.load(Minosoft.MINOSOFT_ASSETS_MANAGER)
this.hudAtlasElements = HUDAtlasElement.deserialize(Minosoft.MINOSOFT_ASSETS_MANAGER.readJsonAsset(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "mapping/atlas.json")).toResourceLocationMap(), renderWindow.textures.allTextures)
hudAtlasElements = HUDAtlasElement.deserialize(Minosoft.MINOSOFT_ASSETS_MANAGER.readJsonAsset(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "mapping/atlas.json")).toResourceLocationMap(), renderWindow.textures.allTextures)
registerDefaultElements()
registerElements()
renderWindow.inputHandler.registerKeyCallback(KeyBindingsNames.TOGGLE_HUD) {
hudEnabled = !hudEnabled
}
for ((_, element) in hudElements.values) {
element.init()
}
renderWindow.inputHandler.registerKeyCallback(KeyBindingsNames.CLOSE) {
}
connection.registerEvent(CallbackEventInvoker.of<ScreenResizeEvent> {
orthographicMatrix = glm.ortho(-it.screenDimensions.x / 2.0f, it.screenDimensions.x / 2.0f, -it.screenDimensions.y / 2.0f, it.screenDimensions.y / 2.0f)
for ((_, hudElement) in hudElements.values) {
hudElement.layout.clearChildrenCache()
orthographicMatrix = glm.ortho(0f, renderWindow.screenDimensions.x.toFloat(), renderWindow.screenDimensions.y.toFloat(), 0f)
for (hudElement in hudElements.values) {
hudElement.prepare(orthographicMatrix)
}
})
}
private fun registerDefaultElements() {
addElement(BreakProgressHUDElement)
addElement(CrosshairHUDElement)
addElement(HUDWorldDebugNode)
addElement(HUDSystemDebugNode)
addElement(ChatBoxHUDElement)
}
fun addElement(builder: HUDRenderBuilder<*>) {
var needToSafeConfig = false
val properties = Minosoft.getConfig().config.game.elements.entries.getOrPut(builder.RESOURCE_LOCATION) {
needToSafeConfig = true
builder.DEFAULT_PROPERTIES
private fun registerElements() {
for ((resourceLocation, hudElement) in Minosoft.getConfig().config.game.elements.entries.entries) {
hudElements[resourceLocation] = hudElement
enabledHUDElements[resourceLocation] = hudElement
hudElement.init(this)
}
if (needToSafeConfig) {
Minosoft.getConfig().saveToFile()
}
val hudElement = builder.build(this)
hudElement.properties = properties
val pair = Pair(properties, hudElement)
hudElements[builder.RESOURCE_LOCATION] = pair
properties.toggleKeyBinding?.let {
// register key binding
renderWindow.inputHandler.registerKeyCallback(it) {
// ToDo: Use sticky
if (enabledHUDElement.contains(builder.RESOURCE_LOCATION)) {
enabledHUDElement.remove(builder.RESOURCE_LOCATION)
} else {
enabledHUDElement[builder.RESOURCE_LOCATION] = pair
}
forcePrepare = true
}
}
if (properties.enabled) {
enabledHUDElement[builder.RESOURCE_LOCATION] = pair
forcePrepare = true
}
}
fun removeElement(resourceLocation: ResourceLocation) {
val element = hudElements[resourceLocation] ?: return
element.first.toggleKeyBinding?.let {
renderWindow.inputHandler.unregisterKeyBinding(it)
}
enabledHUDElement.remove(resourceLocation)
hudElements.remove(resourceLocation)
forcePrepare = true
}
override fun postInit() {
@ -145,74 +82,17 @@ class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow
renderWindow.textures.use(hudShader)
for (element in hudElements.values) {
element.second.postInit()
element.postInit()
}
}
override fun draw() {
if (!RenderConstants.RENDER_HUD) {
return
}
if (!hudEnabled) {
return
}
var needsUpdate = false
val tempMesh = HUDMesh()
for ((_, hudElement) in enabledHUDElement.values) {
hudElement.draw()
if (hudElement.layout.needsCacheUpdate()) {
needsUpdate = true
// break
if (RenderConstants.RENDER_HUD && hudEnabled) {
hudShader.use()
for (hudElement in enabledHUDElements.values) {
hudElement.draw()
}
}
if (forcePrepare || needsUpdate) {
for ((elementProperties, hudElement) in enabledHUDElement.values) {
val realScaleFactor = elementProperties.scale * Minosoft.getConfig().config.game.hud.scale
val realSize = hudElement.layout.sizing.currentSize * realScaleFactor
realSize.x = MMath.clamp(realSize.x, hudElement.layout.sizing.minSize.x, hudElement.layout.sizing.maxSize.x)
realSize.y = MMath.clamp(realSize.y, hudElement.layout.sizing.minSize.y, hudElement.layout.sizing.maxSize.y)
val elementStart = getRealPosition(realSize, elementProperties, renderWindow.screenDimensions)
hudElement.layout.checkCache(elementStart, realScaleFactor, orthographicMatrix, 0)
tempMesh.addCacheMesh(hudElement.layout.cache)
}
currentHUDMesh.unload(false)
tempMesh.load()
currentHUDMesh = tempMesh
}
hudShader.use()
currentHUDMesh.draw()
}
private fun getRealPosition(elementSize: Vec2i, elementProperties: HUDElementProperties, screenDimensions: Vec2i): Vec2i {
val halfScreenDimensions = screenDimensions / 2
val halfElementSize = elementSize / 2
val realPosition = elementProperties.position * halfScreenDimensions
var x = realPosition.x
var y = realPosition.y
if (elementProperties.xBinding == HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY) {
if (elementProperties.position.x >= 0) {
x -= elementSize.x
}
} else {
x -= halfElementSize.x
}
if (elementProperties.yBinding == HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY) {
if (elementProperties.position.y < 0) {
y += elementSize.y
}
} else {
y += halfElementSize.y
}
return Vec2i(x, y)
}
companion object : RendererBuilder<HUDRenderer> {

View File

@ -32,6 +32,14 @@ data class HUDAtlasElement(
override val size: Vec2i
get() = binding.size
val uvs: Array<Vec2> 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

View File

@ -25,7 +25,6 @@ data class Vec2Binding(
val size: Vec2i = glm.abs(start - end)
companion object {
fun deserialize(json: JsonElement): Vec2Binding {
check(json is JsonObject)

View File

@ -1,146 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.elements.input
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.hud.nodes.layout.AbsoluteLayout
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.LabelNode
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeSizing
import de.bixilon.minosoft.util.MMath
import glm_.vec2.Vec2i
open class TextField(
renderWindow: RenderWindow,
val properties: TextFieldProperties,
sizing: NodeSizing = NodeSizing(),
) : AbsoluteLayout(renderWindow, sizing = sizing), KeyConsumer, MouseConsumer {
private var textBuilder: StringBuilder = StringBuilder(properties.defaultText)
val textElement = LabelNode(renderWindow, sizing = sizing.copy(), text = ChatComponent.of(text))
private var position = text.length
var text: String
get() = textBuilder.toString()
set(value) {
position = value.length
textBuilder = StringBuilder(value)
update()
}
init {
addChild(Vec2i(0, 0), textElement)
clearChildrenCache()
}
fun clearText() {
textBuilder.clear()
update()
}
private fun update() {
textElement.text = ChatComponent.of(text)
}
override fun keyInput(keyCodes: KeyCodes) {
when (keyCodes) {
KeyCodes.KEY_BACKSPACE -> {
if (textBuilder.isEmpty() || position == 0) {
return
}
textBuilder.deleteCharAt(--position)
}
KeyCodes.KEY_DELETE -> {
if (textBuilder.isEmpty() || position == textBuilder.length) {
return
}
textBuilder.deleteCharAt(position)
}
KeyCodes.KEY_ENTER -> {
if (renderWindow.inputHandler.isKeyDown(KeyCodes.KEY_LEFT_CONTROL, KeyCodes.KEY_RIGHT_CONTROL, KeyCodes.KEY_LEFT_SHIFT, KeyCodes.KEY_RIGHT_SHIFT)) {
// new line
if (position > properties.maxLength) {
return
}
textBuilder.insert(position++, '\n')
return
}
properties.onSubmit(text)
if (properties.submitCloses) {
properties.onClose()
}
text = properties.defaultText
}
KeyCodes.KEY_LEFT -> {
position = MMath.clamp(position - 1, 0, text.length)
return
}
KeyCodes.KEY_RIGHT -> {
position = MMath.clamp(position + 1, 0, text.length)
return
}
KeyCodes.KEY_V -> {
if (renderWindow.inputHandler.isKeyDown(KeyCodes.KEY_LEFT_CONTROL, KeyCodes.KEY_RIGHT_CONTROL)) {
// paste
textInput(renderWindow.getClipboardText())
}
}
// ToDo: Up and down for line breaks, shift and ctrl modifier, ...
else -> {
return
}
}
update()
super.keyInput(keyCodes)
}
override fun tick(tick: Long) {
if ((tick / FIELD_CURSOR_BLINK_INTERVAL) % 2L == 0L && position == text.length) {
textElement.sText = "$textBuilder" + "_"
} else {
textElement.sText = textBuilder.toString()
}
}
override fun close() {
properties.onClose()
}
override fun charInput(char: Char) {
if (position >= properties.maxLength) {
return
}
val previous = textBuilder.toString()
textBuilder.insert(position++, char.toString())
properties.onInput(previous, textBuilder.toString())
update()
}
fun textInput(text: String) {
if (position >= properties.maxLength) {
return
}
val length = MMath.clamp(text.length, 0, properties.maxLength - position)
val previous = textBuilder.toString()
textBuilder.insert(position, text.substring(0, length))
position += length
properties.onInput(previous, textBuilder.toString())
update()
}
companion object {
const val FIELD_CURSOR_BLINK_INTERVAL = 8
}
}

View File

@ -1,23 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.elements.input
data class TextFieldProperties(
var defaultText: String = "",
var maxLength: Int = 256,
var onSubmit: (text: String) -> Unit = {},
var onClose: () -> Unit = {},
var onInput: (previousText: String, nextText: String) -> Unit = { _, _ -> },
var submitCloses: Boolean = false,
)

View File

@ -1,67 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.elements.other
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.hud.HUDElementProperties
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderBuilder
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.nodes.HUDElement
import de.bixilon.minosoft.gui.rendering.hud.nodes.layout.AbsoluteLayout
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.LabelNode
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
class BreakProgressHUDElement(
hudRenderer: HUDRenderer,
) : HUDElement(hudRenderer) {
override val layout = AbsoluteLayout(hudRenderer.renderWindow)
private val text: LabelNode = LabelNode(hudRenderer.renderWindow)
override fun init() {
layout.addChild(Vec2i(0, 0), text)
}
override fun draw() {
val currentProgress = hudRenderer.renderWindow.inputHandler.leftClickHandler.breakProgress
if (currentProgress in 0.0..1.0) {
val textComponent = TextComponent("${(currentProgress * 100).toInt()}%")
textComponent.color(when {
currentProgress < 0.3 -> ChatColors.RED
currentProgress < 0.7 -> ChatColors.YELLOW
else -> ChatColors.GREEN
})
text.text = textComponent
} else {
// Toggle visibility?
text.sText = ""
}
}
companion object : HUDRenderBuilder<BreakProgressHUDElement> {
override val RESOURCE_LOCATION = ResourceLocation("minosoft:break_progress")
override val DEFAULT_PROPERTIES = HUDElementProperties(
position = Vec2(0.08f, 0.0f),
xBinding = HUDElementProperties.PositionBindings.CENTER,
yBinding = HUDElementProperties.PositionBindings.CENTER,
)
override fun build(hudRenderer: HUDRenderer): BreakProgressHUDElement {
return BreakProgressHUDElement(hudRenderer)
}
}
}

View File

@ -1,51 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.elements.other
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.gui.rendering.hud.HUDElementProperties
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderBuilder
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.nodes.HUDElement
import de.bixilon.minosoft.gui.rendering.hud.nodes.layout.AbsoluteLayout
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.ImageNode
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeSizing
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
class CrosshairHUDElement(
hudRenderer: HUDRenderer,
) : HUDElement(hudRenderer) {
override val layout = AbsoluteLayout(hudRenderer.renderWindow)
private lateinit var crosshairImage: ImageNode
override fun init() {
val atlasElement = hudRenderer.hudAtlasElements[ResourceLocation("minecraft:crosshair")]!!
crosshairImage = ImageNode(hudRenderer.renderWindow, NodeSizing(minSize = atlasElement.binding.size), textureLike = atlasElement)
layout.addChild(Vec2i(0, 0), crosshairImage)
}
companion object : HUDRenderBuilder<CrosshairHUDElement> {
override val RESOURCE_LOCATION = ResourceLocation("minosoft:crosshair")
override val DEFAULT_PROPERTIES = HUDElementProperties(
position = Vec2(0.0f, 0.0f),
xBinding = HUDElementProperties.PositionBindings.CENTER,
yBinding = HUDElementProperties.PositionBindings.CENTER,
)
override fun build(hudRenderer: HUDRenderer): CrosshairHUDElement {
return CrosshairHUDElement(hudRenderer)
}
}
}

View File

@ -1,79 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes.chat
import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.gui.rendering.hud.HUDElementProperties
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderBuilder
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.elements.input.TextField
import de.bixilon.minosoft.gui.rendering.hud.elements.input.TextFieldProperties
import de.bixilon.minosoft.gui.rendering.hud.nodes.HUDElement
import de.bixilon.minosoft.gui.rendering.hud.nodes.layout.AbsoluteLayout
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
class ChatBoxHUDElement(hudRenderer: HUDRenderer) : HUDElement(hudRenderer) {
override val layout = AbsoluteLayout(hudRenderer.renderWindow)
private lateinit var inputField: TextField
override fun init() {
inputField = TextField(
renderWindow = hudRenderer.renderWindow,
properties = TextFieldProperties(
maxLength = 256,
submitCloses = true,
onSubmit = { hudRenderer.renderWindow.connection.sender.sendChatMessage(it) },
onClose = { closeChat() },
),
)
layout.addChild(Vec2i(0, 0), inputField)
inputField.apply()
hudRenderer.renderWindow.inputHandler.registerKeyCallback(KeyBindingsNames.OPEN_CHAT) {
openChat()
}
hudRenderer.connection.registerEvent(CallbackEventInvoker.of<ScreenResizeEvent> {
layout.sizing.minSize.x = it.screenDimensions.x
layout.sizing.maxSize.x = it.screenDimensions.x
inputField.textElement.setProperties.hardWrap = (inputField.textElement.sizing.minSize.x / scale).toInt()
layout.apply()
})
}
fun openChat() {
hudRenderer.renderWindow.inputHandler.currentKeyConsumer = inputField
}
fun closeChat() {
hudRenderer.renderWindow.inputHandler.currentKeyConsumer = null
}
companion object : HUDRenderBuilder<ChatBoxHUDElement> {
override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("minosoft:chat")
override val DEFAULT_PROPERTIES = HUDElementProperties(
position = Vec2(0.0f, -1.0f),
xBinding = HUDElementProperties.PositionBindings.CENTER,
)
override fun build(hudRenderer: HUDRenderer): ChatBoxHUDElement {
return ChatBoxHUDElement(hudRenderer)
}
}
}

View File

@ -1,31 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes.debug
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.nodes.HUDElement
import de.bixilon.minosoft.gui.rendering.hud.nodes.layout.RowLayout
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.LabelNode
abstract class DebugScreenNode(hudRenderer: HUDRenderer) : HUDElement(hudRenderer) {
override val layout = RowLayout(hudRenderer.renderWindow)
protected var lastPrepareTime = 0L
fun text(text: String = ""): LabelNode {
val textElement = LabelNode(hudRenderer.renderWindow, text = ChatComponent.of(text))
layout.addRow(textElement)
return textElement
}
}

View File

@ -1,141 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes.debug
import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.gui.rendering.hud.HUDElementProperties
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderBuilder
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeAlignment
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import de.bixilon.minosoft.modding.loading.ModLoader
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.GitInfo
import de.bixilon.minosoft.util.SystemInformation
import de.bixilon.minosoft.util.UnitFormatter
import glm_.vec2.Vec2
import org.lwjgl.opengl.GL11.*
class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer) {
init {
layout.sizing.forceAlign = NodeAlignment.RIGHT
layout.sizing.padding.top = 2
layout.sizing.padding.right = 2
text("Java: ${Runtime.version()} ${System.getProperty("sun.arch.data.model")}bit")
}
private val memoryText = text("TBA")
private val allocatedMemoryText = text("TBA")
init {
text("System: ${SystemInformation.SYSTEM_MEMORY_TEXT}")
text()
text("OS: ${SystemInformation.OS_TEXT}")
text("CPU: ${SystemInformation.PROCESSOR_TEXT}")
text()
}
private val displayText = text("TBA")
private val gpuText = text("TBA")
private val gpuVersionText = text("TBA")
init {
text()
text(
if (GitInfo.IS_INITIALIZED) {
"Commit: ${GitInfo.GIT_COMMIT_ID_DESCRIBE}: ${GitInfo.GIT_COMMIT_MESSAGE_SHORT}"
} else {
"GitInfo uninitialized :("
})
text()
text("Mods: ${ModLoader.MOD_MAP.size} active, ${hudRenderer.connection.eventListenerSize} listeners")
}
private val targetPosition = text("TBA")
private val targetBlockState = text("TBA")
override fun init() {
gpuText.sText = "GPU: " + (glGetString(GL_RENDERER) ?: "unknown")
gpuVersionText.sText = "Version: " + (glGetString(GL_VERSION) ?: "unknown")
hudRenderer.connection.registerEvent(CallbackEventInvoker.of<ScreenResizeEvent> {
displayText.sText = "Display: ${getScreenDimensions()}"
})
}
override fun draw() {
if (System.currentTimeMillis() - lastPrepareTime < ProtocolDefinition.TICK_TIME * 2) {
return
}
memoryText.sText = "Memory: ${getUsedMemoryPercent()}% ${getFormattedUsedMemory()}/${SystemInformation.MAX_MEMORY_TEXT}"
allocatedMemoryText.sText = "Allocated: ${getAllocatedMemoryPercent()}% ${getFormattedAllocatedMemory()}"
val rayCastHit = hudRenderer.renderWindow.inputHandler.camera.getTargetBlock()
if (rayCastHit == null) {
targetPosition.sText = ""
targetBlockState.sText = ""
} else {
targetPosition.sText = "Target block: ${rayCastHit.blockPosition}"
targetBlockState.sText = rayCastHit.blockState.toString()
}
lastPrepareTime = System.currentTimeMillis()
}
private fun getUsedMemory(): Long {
return SystemInformation.RUNTIME.totalMemory() - SystemInformation.RUNTIME.freeMemory()
}
private fun getFormattedUsedMemory(): String {
return UnitFormatter.formatBytes(getUsedMemory())
}
private fun getAllocatedMemory(): Long {
return SystemInformation.RUNTIME.totalMemory()
}
private fun getFormattedAllocatedMemory(): String {
return UnitFormatter.formatBytes(getAllocatedMemory())
}
private fun getUsedMemoryPercent(): Long {
return getUsedMemory() * 100 / SystemInformation.RUNTIME.maxMemory()
}
private fun getAllocatedMemoryPercent(): Long {
return getAllocatedMemory() * 100 / SystemInformation.RUNTIME.maxMemory()
}
private fun getScreenDimensions(): String {
return "${hudRenderer.renderWindow.screenDimensions.x}x${hudRenderer.renderWindow.screenDimensions.y}"
}
companion object : HUDRenderBuilder<HUDSystemDebugNode> {
override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("minosoft:system_debug_screen")
override val DEFAULT_PROPERTIES = HUDElementProperties(
position = Vec2(1.0f, 1.0f),
toggleKeyBinding = KeyBindingsNames.TOGGLE_DEBUG_SCREEN,
enabled = false,
)
override fun build(hudRenderer: HUDRenderer): HUDSystemDebugNode {
return HUDSystemDebugNode(hudRenderer)
}
}
}

View File

@ -1,163 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes.debug
import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.gui.rendering.chunk.WorldRenderer
import de.bixilon.minosoft.gui.rendering.hud.HUDElementProperties
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderBuilder
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeAlignment
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.UnitFormatter
import glm_.vec2.Vec2
import java.util.*
class HUDWorldDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer) {
private val camera = hudRenderer.renderWindow.inputHandler.camera
private val worldRenderer = hudRenderer.renderWindow.rendererMap[WorldRenderer.RESOURCE_LOCATION] as WorldRenderer?
init {
layout.sizing.forceAlign = NodeAlignment.LEFT
layout.sizing.padding.left = 2
layout.sizing.padding.top = 2
text("§cMinosoft 0.1-pre1")
}
private val fpsText = text("TBA")
private val timingsText = text("TBA")
private val chunksText = text("TBA")
private val openGLText = text("TBA")
init {
text("Connected to ${hudRenderer.connection.address} on ${hudRenderer.connection.version} with ${hudRenderer.connection.account.username}")
text("")
}
private val positionText = text("TBA")
private val blockPositionText = text("TBA")
private val chunkPositionText = text("TBA")
private val facingText = text("TBA")
private val gamemodeText = text("TBA")
private val dimensionText = text("TBA")
private val biomeText = text("TBA")
init {
text()
}
private val difficultyText = text("TBA")
private val lightText = text("TBA")
override fun draw() {
if (System.currentTimeMillis() - lastPrepareTime < ProtocolDefinition.TICK_TIME * 2) {
return
}
fpsText.sText = "FPS: ${getFPS()}"
chunksText.sText = "Chunks: q=${worldRenderer?.queuedChunks?.size} v=${worldRenderer?.visibleChunks?.size} p=${worldRenderer?.allChunkSections?.size} t=${hudRenderer.connection.world.chunks.size}"
timingsText.sText = "Timings: avg ${getAvgFrameTime()}ms, min ${getMinFrameTime()}ms, max ${getMaxFrameTime()}ms"
openGLText.sText = "GL: m=${worldRenderer?.meshes?.let { UnitFormatter.formatNumber(it) }} t=${worldRenderer?.triangles?.let { UnitFormatter.formatNumber(it) }}"
// ToDo: Prepare on change
gamemodeText.sText = "Gamemode: ${hudRenderer.connection.player.entity.gamemode.name.lowercase(Locale.getDefault())}"
positionText.sText = "XYZ ${getPosition()}"
blockPositionText.sText = "Block ${getBlockPosition()}"
chunkPositionText.sText = "Chunk ${getChunkLocation()}"
facingText.sText = "Facing: ${getFacing()}"
biomeText.sText = "Biome: ${camera.currentBiome}"
dimensionText.sText = "Dimension: ${hudRenderer.connection.world.dimension}"
difficultyText.sText = "Difficulty: ${hudRenderer.connection.world.difficulty?.name?.lowercase(Locale.getDefault())}, ${
if (hudRenderer.connection.world.difficultyLocked) {
"locked"
} else {
"unlocked"
}
}"
lightText.sText = "Client light: sky=${hudRenderer.connection.world.worldLightAccessor.getSkyLight(camera.blockPosition)}, block=${hudRenderer.connection.world.worldLightAccessor.getBlockLight(camera.blockPosition)}"
lastPrepareTime = System.currentTimeMillis()
}
private fun nanoToMillis1d(nanos: Long): String {
return "%.1f".format(nanos / 1E6f)
}
private fun getFPS(): String {
val renderStats = hudRenderer.renderWindow.renderStats
return "${renderStats.fpsLastSecond}"
}
private fun getAvgFrameTime(): String {
return nanoToMillis1d(hudRenderer.renderWindow.renderStats.avgFrameTime)
}
private fun getMinFrameTime(): String {
return nanoToMillis1d(hudRenderer.renderWindow.renderStats.minFrameTime)
}
private fun getMaxFrameTime(): String {
return nanoToMillis1d(hudRenderer.renderWindow.renderStats.maxFrameTime)
}
private fun getPosition(): String {
return "${formatCoordinate(camera.playerEntity.position.x)} / ${formatCoordinate(camera.playerEntity.position.y)} / ${formatCoordinate(camera.playerEntity.position.z)}"
}
private fun getBlockPosition(): String {
return "${camera.blockPosition.x} / ${camera.blockPosition.y} / ${camera.blockPosition.z}"
}
private fun getChunkLocation(): String {
return "${camera.inChunkSectionPosition.x} ${camera.inChunkSectionPosition.y} ${camera.inChunkSectionPosition.z} in ${camera.chunkPosition.x} ${camera.sectionHeight} ${camera.chunkPosition.y}"
}
private fun getFacing(): String {
val yaw = hudRenderer.renderWindow.inputHandler.camera.playerEntity.rotation.yaw
val pitch = hudRenderer.renderWindow.inputHandler.camera.playerEntity.rotation.pitch
val direction = Directions.byDirection(camera.cameraFront)
return "${Directions.byDirection(camera.cameraFront).name.lowercase(Locale.getDefault())} ${direction.directionVector} (${formatRotation(yaw.toDouble())} / ${formatRotation(pitch.toDouble())})"
}
companion object : HUDRenderBuilder<HUDWorldDebugNode> {
override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("minosoft:world_debug_screen")
override val DEFAULT_PROPERTIES = HUDElementProperties(
position = Vec2(-1.0f, 1.0f),
toggleKeyBinding = KeyBindingsNames.TOGGLE_DEBUG_SCREEN,
enabled = false,
)
override fun build(hudRenderer: HUDRenderer): HUDWorldDebugNode {
return HUDWorldDebugNode(hudRenderer)
}
fun formatCoordinate(coordinate: Float): String {
return "%.3f".format(coordinate)
}
fun formatRotation(rotation: Double): String {
return "%.1f".format(rotation)
}
}
}

View File

@ -1,139 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes.layout
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.Node
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeAlignment
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeSizing
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
import de.bixilon.minosoft.util.MMath
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2i
open class AbsoluteLayout(
renderWindow: RenderWindow,
sizing: NodeSizing = NodeSizing(),
initialCacheSize: Int = DEFAULT_INITIAL_CACHE_SIZE,
) : Layout(renderWindow, sizing, initialCacheSize) {
private val children: MutableMap<Node, Vec2i> = synchronizedMapOf()
override fun clearChildren() {
children.clear()
}
fun addChild(start: Vec2i, child: Node) {
child.parent = this
child.apply()
if (children.isEmpty()) {
start.x += child.sizing.margin.left + sizing.padding.left
start.y += child.sizing.margin.top + sizing.padding.top
}
children[child] = start
apply()
}
override fun recursiveApply() {
for ((child, _) in children.toSynchronizedMap()) {
if (child is AbsoluteLayout) {
child.recursiveApply()
} else {
child.apply()
}
}
}
override fun checkAlignment() {
when (sizing.forceAlign) {
NodeAlignment.RIGHT -> {
for ((child, start) in children.toSynchronizedMap()) {
start.x = sizing.currentSize.x - (child.sizing.margin.right + sizing.padding.right + child.sizing.currentSize.x)
}
}
NodeAlignment.LEFT -> {
for ((child, start) in children.toSynchronizedMap()) {
start.x = child.sizing.margin.left + sizing.padding.left
}
}
NodeAlignment.CENTER -> {
for ((child, start) in children.toSynchronizedMap()) {
start.x = (sizing.currentSize.x - child.sizing.currentSize.x) / 2
}
}
}
}
override fun apply() {
sizing.validate()
clearCache()
recalculateSize()
checkAlignment()
parent?.apply()
}
override fun recalculateSize() {
sizing.currentSize = Vec2i(sizing.minSize)
for ((childNode, start) in children.toSynchronizedMap()) {
checkSize(childNode, start)
}
}
override fun clearCache() {
cache.clear()
parent?.clearCache()
}
private fun checkSize(child: Node, start: Vec2i) {
var changed = false
val end = start + child.sizing.currentSize
if (end.x > sizing.currentSize.x) {
sizing.currentSize.x = MMath.clamp(end.x, sizing.minSize.x, sizing.maxSize.x)
changed = true
}
if (end.y > sizing.currentSize.y) {
sizing.currentSize.y = MMath.clamp(end.y, sizing.minSize.y, sizing.maxSize.y)
changed = true
}
if (changed) {
clearCache()
}
}
private fun addToStart(start: Vec2i, elementPosition: Vec2i): Vec2i {
return Vec2i(start.x + elementPosition.x, start.y - elementPosition.y)
}
override fun prepareCache(start: Vec2i, scaleFactor: Float, matrix: Mat4, z: Int) {
for ((child, childStart) in children.toSynchronizedMap()) {
child.checkCache(addToStart(start, childStart * scaleFactor), scaleFactor, matrix, z)
cache.addCache(child.cache)
}
}
override fun clearChildrenCache() {
for ((child, _) in children.toSynchronizedMap()) {
if (child is AbsoluteLayout) {
child.clearChildrenCache()
} else {
child.clearCache()
}
}
clearCache()
}
override fun removeChild(node: Node) {
children.remove(node)
}
}

View File

@ -1,37 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes.layout
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.Node
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeSizing
abstract class Layout(
renderWindow: RenderWindow,
sizing: NodeSizing = NodeSizing(),
initialCacheSize: Int = DEFAULT_INITIAL_CACHE_SIZE,
) : Node(renderWindow, sizing, initialCacheSize) {
abstract fun clearChildren()
abstract fun recursiveApply()
abstract fun checkAlignment()
abstract fun recalculateSize()
abstract fun clearChildrenCache()
abstract fun removeChild(node: Node)
}

View File

@ -1,31 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes.layout
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.Node
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeSizing
import glm_.vec2.Vec2i
class RowLayout(
renderWindow: RenderWindow,
sizing: NodeSizing = NodeSizing(),
initialCacheSize: Int = DEFAULT_INITIAL_CACHE_SIZE,
) : AbsoluteLayout(renderWindow, sizing, initialCacheSize) {
fun addRow(node: Node) {
addChild(Vec2i(0, sizing.currentSize.y + node.sizing.margin.top + node.sizing.padding.top), node)
apply()
}
}

View File

@ -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<Vec2i>) {
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<ResourceLocation, HUDElementPositionAnchors>()
for (hudPositionAttachmentOption in HUD_ELEMENT_POSITION_ATTACHMENT_OPTIONS) {
result[hudPositionAttachmentOption.resourceLocation] = hudPositionAttachmentOption
}
result
}
}
}

View File

@ -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<ResourceLocation, HUDElementPositionUnits>()
for (unit in HUD_ELEMENT_POSITION_UNITS) {
result[unit.resourceLocation] = unit
}
result
}
const val TOTAL_UNITS = 100f
}
}

View File

@ -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)
}
}
}

View File

@ -11,22 +11,32 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes
package de.bixilon.minosoft.gui.rendering.hud.nodes.primitive
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.gui.rendering.hud.HUDElementProperties
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.layout.Layout
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(protected val hudRenderer: HUDRenderer) {
abstract val layout: Layout
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
lateinit var properties: HUDElementProperties
open fun init(hudRenderer: HUDRenderer) {
this.hudRenderer = hudRenderer
}
val scale: Float
get() = properties.scale * Minosoft.getConfig().config.game.hud.scale
open fun init() {}
open fun postInit() {}
open fun draw() {}
open fun prepare(matrix: Mat4) {}
}

View File

@ -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<String, Any>): 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!
)
}

View File

@ -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()
}
}

View File

@ -1,67 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* 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.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.hud.atlas.TextureLike
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeSizing
import de.bixilon.minosoft.gui.rendering.util.mesh.SimpleTextureMesh
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
import glm_.vec3.Vec3
import glm_.vec4.Vec4
class ImageNode(
renderWindow: RenderWindow,
sizing: NodeSizing = NodeSizing(),
var textureLike: TextureLike?,
val z: Int = 0,
val tintColor: RGBColor? = null,
) : Node(renderWindow, sizing = sizing, initialCacheSize = SimpleTextureMesh.SimpleTextureMeshStruct.FLOATS_PER_VERTEX * 6) {
private fun addToStart(start: Vec2i, elementPosition: Vec2i): Vec2i {
return Vec2i(start.x + elementPosition.x, start.y - elementPosition.y)
}
private fun addToEnd(start: Vec2i, elementPosition: Vec2i): Vec2i {
return Vec2i(start.x + elementPosition.x, start.y - elementPosition.y)
}
override fun apply() {}
override fun prepareCache(start: Vec2i, scaleFactor: Float, matrix: Mat4, z: Int) {
val modelStart = matrix * Vec4(RenderConstants.PIXEL_UV_PIXEL_ADD + start, 1.0f, 1.0f)
val ourEnd = addToEnd(start, sizing.currentSize * scaleFactor)
val modelEnd = matrix * Vec4(RenderConstants.PIXEL_UV_PIXEL_ADD + ourEnd, 1.0f, 1.0f)
val uvStart = textureLike?.uvStart ?: Vec2()
val uvEnd = textureLike?.uvEnd ?: Vec2()
val realZ = RenderConstants.HUD_Z_COORDINATE + RenderConstants.HUD_Z_COORDINATE_Z_FACTOR * (this.z + z)
fun addVertex(positionX: Float, positionY: Float, textureUV: Vec2) {
cache.addVertex(Vec3(positionX, positionY, realZ), textureUV, textureLike?.texture, tintColor)
}
addVertex(modelStart.x, modelStart.y, Vec2(uvStart.x, uvStart.y))
addVertex(modelStart.x, modelEnd.y, Vec2(uvStart.x, uvEnd.y))
addVertex(modelEnd.x, modelStart.y, Vec2(uvEnd.x, uvStart.y))
addVertex(modelStart.x, modelEnd.y, Vec2(uvStart.x, uvEnd.y))
addVertex(modelEnd.x, modelEnd.y, Vec2(uvEnd.x, uvEnd.y))
addVertex(modelEnd.x, modelStart.y, Vec2(uvEnd.x, uvStart.y))
}
}

View File

@ -1,72 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* 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.text.ChatComponent
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.font.text.TextGetProperties
import de.bixilon.minosoft.gui.rendering.font.text.TextSetProperties
import de.bixilon.minosoft.gui.rendering.hud.nodes.layout.AbsoluteLayout
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeSizing
import glm_.vec2.Vec2i
class LabelNode(
renderWindow: RenderWindow,
sizing: NodeSizing = NodeSizing(minSize = Vec2i(0, Font.CHAR_HEIGHT + 2 * TEXT_BACKGROUND_OFFSET)),
text: ChatComponent = ChatComponent.of(""),
var background: Boolean = true,
val setProperties: TextSetProperties = TextSetProperties(),
) : AbsoluteLayout(renderWindow, sizing) {
var getProperties = TextGetProperties()
private set
var text: ChatComponent = text
set(value) {
field = value
prepare()
}
var sText: String
get() = text.message
set(value) {
text = ChatComponent.of(value)
}
init {
prepare()
}
private fun prepare() {
clearChildren()
getProperties = TextGetProperties()
val textStartPosition = Vec2i(TEXT_BACKGROUND_OFFSET, TEXT_BACKGROUND_OFFSET)
text.prepareRender(textStartPosition, Vec2i(), renderWindow, this, 1, setProperties, getProperties)
if (background && text.message.isNotBlank()) {
drawBackground(getProperties.size + textStartPosition + TEXT_BACKGROUND_OFFSET)
}
apply()
}
private fun drawBackground(end: Vec2i, z: Int = 1, tintColor: RGBColor = RenderConstants.TEXT_BACKGROUND_COLOR) {
addChild(Vec2i(0, 0), ImageNode(renderWindow, NodeSizing(minSize = end), renderWindow.WHITE_TEXTURE, 0, tintColor))
}
companion object {
private const val TEXT_BACKGROUND_OFFSET = 1
}
}

View File

@ -1,52 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* 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.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.hud.HUDCacheMesh
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeSizing
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2i
abstract class Node(
val renderWindow: RenderWindow,
val sizing: NodeSizing = NodeSizing(),
initialCacheSize: Int = DEFAULT_INITIAL_CACHE_SIZE,
) {
val cache = HUDCacheMesh(initialCacheSize)
open var parent: Node? = null
abstract fun apply()
fun needsCacheUpdate(): Boolean {
return cache.isEmpty()
}
fun checkCache(start: Vec2i, scaleFactor: Float, matrix: Mat4, z: Int = 1) {
if (!needsCacheUpdate()) {
return
}
prepareCache(start, scaleFactor, matrix, z)
}
open fun clearCache() {
cache.clear()
}
abstract fun prepareCache(start: Vec2i, scaleFactor: Float, matrix: Mat4, z: Int = 1)
companion object {
const val DEFAULT_INITIAL_CACHE_SIZE = 1000
}
}

View File

@ -1,21 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes.properties
enum class NodeAlignment {
LEFT,
RIGHT,
CENTER,
}

View File

@ -1,40 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes.properties
import de.bixilon.minosoft.util.MMath
import glm_.vec2.Vec2i
data class NodeSizing(
var minSize: Vec2i = Vec2i(0, 0),
var maxSize: Vec2i = Vec2i(Int.MAX_VALUE, Int.MAX_VALUE),
var margin: Spacing = Spacing(0, 0, 0, 0),
var padding: Spacing = Spacing(0, 0, 0, 0),
var forceAlign: NodeAlignment? = null,
) {
var currentSize: Vec2i = Vec2i(minSize)
fun validate() {
MMath.clamp(currentSize, minSize, maxSize)
}
var forceSize: Vec2i
get() = currentSize
set(value) {
minSize = value
maxSize = value
validate()
}
}

View File

@ -1,21 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.hud.nodes.properties
data class Spacing(
var top: Int = 0,
var right: Int = 0,
var bottom: Int = 0,
var left: Int = 0,
)

View File

@ -328,4 +328,20 @@ object VecUtil {
Axes.Z -> this.z
}
}
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")
}
}
}

View File

@ -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.textures.properties.ImageProperties
object JSONSerializer {
@ -27,6 +28,7 @@ object JSONSerializer {
.add(AccountSerializer)
.add(ServerSerializer)
.add(ResourceLocationSerializer)
.add(HUDElementSerializer)
.add(KotlinJsonAdapterFactory())
.build()!!