wip item rendering, hud fixes

This commit is contained in:
Bixilon 2021-10-21 16:41:51 +02:00
parent 4a05a34ef3
commit e1bdd71e5e
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
14 changed files with 167 additions and 47 deletions

View File

@ -39,7 +39,7 @@ import de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast
data class ItemStack(
val item: Item,
private val connection: PlayConnection? = null,
var count: Int = 0,
var count: Int = 1,
val enchantments: MutableMap<Enchantment, Int> = mutableMapOf(),
val lore: MutableList<ChatComponent> = mutableListOf(),
var repairCost: Int = 0,

View File

@ -17,7 +17,7 @@ data class Abilities(
var isInvulnerable: Boolean = false,
var isFlying: Boolean = false,
var canFly: Boolean = false,
var canInstantBreak: Boolean = false,
var canInstantBreak: Boolean = false, // ToDo: This is the check if we are in creative mode, but no exactly sure...
var flyingSpeed: Double = 0.05,
var walkingSpeed: Double = 0.1,

View File

@ -55,8 +55,8 @@ class PlayerInventory(connection: PlayConnection) : Container(
}
companion object {
private const val HOTBAR_OFFSET = 36
private const val ARMOR_OFFSET = 5
const val HOTBAR_OFFSET = 36
const val ARMOR_OFFSET = 5
const val HOTBAR_SLOTS = 9
}
}

View File

@ -38,15 +38,10 @@ import java.io.ByteArrayInputStream
class ServerCardController : AbstractCard<ServerCard>() {
@FXML private lateinit var faviconFX: ImageView
@FXML private lateinit var serverNameFX: TextFlow
@FXML private lateinit var motdFX: TextFlow
@FXML private lateinit var pingFX: Label
@FXML private lateinit var playerCountFX: Label
@FXML private lateinit var serverVersionFX: Label

View File

@ -16,15 +16,14 @@ package de.bixilon.minosoft.gui.rendering.font.renderer
import de.bixilon.minosoft.data.text.BaseComponent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import glm_.vec2.Vec2i
object BaseComponentRenderer : ChatComponentRenderer<BaseComponent> {
override fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, z: Int, element: Element, fontAlignment: HorizontalAlignments, renderWindow: RenderWindow, consumer: GUIVertexConsumer?, renderInfo: TextRenderInfo, text: BaseComponent): Boolean {
override fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, z: Int, element: Element, renderWindow: RenderWindow, consumer: GUIVertexConsumer?, renderInfo: TextRenderInfo, text: BaseComponent): Boolean {
for (part in text.parts) {
if (ChatComponentRenderer.render(initialOffset, offset, size, z, element, fontAlignment, renderWindow, consumer, renderInfo, part)) {
if (ChatComponentRenderer.render(initialOffset, offset, size, z, element, renderWindow, consumer, renderInfo, part)) {
return true
}
}

View File

@ -18,7 +18,6 @@ import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import glm_.vec2.Vec2i
@ -27,15 +26,15 @@ interface ChatComponentRenderer<T : ChatComponent> {
/**
* Returns true if the text exceeded the maximum size
*/
fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, z: Int, element: Element, fontAlignment: HorizontalAlignments, renderWindow: RenderWindow, consumer: GUIVertexConsumer?, renderInfo: TextRenderInfo, text: T): Boolean
fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, z: Int, element: Element, renderWindow: RenderWindow, consumer: GUIVertexConsumer?, renderInfo: TextRenderInfo, text: T): Boolean
companion object : ChatComponentRenderer<ChatComponent> {
override fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, z: Int, element: Element, fontAlignment: HorizontalAlignments, renderWindow: RenderWindow, consumer: GUIVertexConsumer?, renderInfo: TextRenderInfo, text: ChatComponent): Boolean {
override fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, z: Int, element: Element, renderWindow: RenderWindow, consumer: GUIVertexConsumer?, renderInfo: TextRenderInfo, text: ChatComponent): Boolean {
return when (text) {
is BaseComponent -> BaseComponentRenderer.render(initialOffset, offset, size, z, element, fontAlignment, renderWindow, consumer, renderInfo, text)
is TextComponent -> TextComponentRenderer.render(initialOffset, offset, size, z, element, fontAlignment, renderWindow, consumer, renderInfo, text)
is BaseComponent -> BaseComponentRenderer.render(initialOffset, offset, size, z, element, renderWindow, consumer, renderInfo, text)
is TextComponent -> TextComponentRenderer.render(initialOffset, offset, size, z, element, renderWindow, consumer, renderInfo, text)
else -> TODO("Don't know how to render ${text::class.java}")
}
}

View File

@ -19,7 +19,6 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.font.CharData
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.util.MMath.ceil
@ -27,7 +26,7 @@ import glm_.vec2.Vec2i
object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
override fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, z: Int, element: Element, fontAlignment: HorizontalAlignments, renderWindow: RenderWindow, consumer: GUIVertexConsumer?, renderInfo: TextRenderInfo, text: TextComponent): Boolean {
override fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, z: Int, element: Element, renderWindow: RenderWindow, consumer: GUIVertexConsumer?, renderInfo: TextRenderInfo, text: TextComponent): Boolean {
if (text.message.isEmpty()) {
return false
}
@ -52,17 +51,17 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
}
fun applyOffset() {
if (consumer == null && offset.x == initialOffset.x + Font.CHAR_MARGIN) {
if (consumer == null && offset.x == initialOffset.x + renderInfo.charMargin) {
// preparing phase
renderInfo.lines += TextLineInfo()
} else {
alignmentXOffset = fontAlignment.getOffset(element.size.x, renderInfo.currentLine.width)
alignmentXOffset = renderInfo.fontAlignment.getOffset(element.size.x, renderInfo.currentLine.width)
}
}
fun addY(height: Int): Boolean {
val nextY = offset.y + height
val nextSizeY = nextY - initialOffset.y + Font.TOTAL_CHAR_HEIGHT // add initial height for chars + end margin
val nextSizeY = nextY - initialOffset.y + renderInfo.charMargin // add initial height for chars + end margin
if (nextSizeY >= elementMaxSize.y) {
return true
}
@ -79,14 +78,14 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
}
pushLine()
renderInfo.currentLineNumber++
offset.x = initialOffset.x + Font.CHAR_MARGIN
offset.x = initialOffset.x + renderInfo.charMargin
applyOffset()
return false
}
fun addX(width: Int, wrap: Boolean = true): Boolean {
val nextX = offset.x + width
val nextSizeX = nextX - initialOffset.x + Font.CHAR_MARGIN // end margin
val nextSizeX = nextX - initialOffset.x + renderInfo.charMargin // end margin
if (nextSizeX > elementMaxSize.x) {
if (!wrap) {
return true
@ -109,13 +108,13 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
if (size.y == 0) {
// Add initial height of the letter for the first line
val nextSizeY = Font.TOTAL_CHAR_HEIGHT
val nextSizeY = renderInfo.charHeight
if (nextSizeY > elementMaxSize.y) {
return true
}
size.y = nextSizeY
size.x += Font.CHAR_MARGIN * 2
offset += Font.CHAR_MARGIN
size.x += renderInfo.charMargin * 2
offset += renderInfo.charMargin
}
applyOffset()
@ -130,7 +129,7 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
}
// skip spaces that are wrapped (because of a line break)
if (offset.y != initialOffset.y + Font.CHAR_MARGIN && offset.x == initialOffset.x + Font.CHAR_MARGIN && char == ' ') {
if (offset.y != initialOffset.y + renderInfo.charMargin && offset.x == initialOffset.x + renderInfo.charMargin && char == ' ') {
continue
}
@ -139,7 +138,7 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
val charWidth = charData.calculateWidth(text)
var width = charWidth
if (offset.x != initialOffset.x + Font.CHAR_MARGIN) {
if (offset.x != initialOffset.x + renderInfo.charMargin) {
// add spacing between letters
width += if (bold) {
Font.HORIZONTAL_SPACING_BOLD

View File

@ -14,11 +14,15 @@
package de.bixilon.minosoft.gui.rendering.font.renderer
import de.bixilon.minosoft.config.StaticConfiguration
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
class TextRenderInfo(
val fontAlignment: HorizontalAlignments,
val charHeight: Int,
val charMargin: Int,
val lines: MutableList<TextLineInfo> = mutableListOf(),
var currentLineNumber: Int = 0,
) {

View File

@ -161,6 +161,9 @@ abstract class Element(val hudRenderer: HUDRenderer) {
*/
@Deprecated("Generally a bad idea to call")
open fun forceApply() {
if (this is Pollable) {
poll()
}
forceSilentApply()
parent?.onChildChange(this)
}

View File

@ -0,0 +1,32 @@
package de.bixilon.minosoft.gui.rendering.gui.elements.items
import de.bixilon.minosoft.data.registries.other.containers.Container
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.atlas.Vec2iBinding
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import glm_.vec2.Vec2i
class ContainerItemsElement(
hudRenderer: HUDRenderer,
val container: Container,
val slots: Map<Int, Vec2iBinding>, // ToDo: Use an array?
) : Element(hudRenderer) {
override var cacheEnabled: Boolean = false
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
for ((slot, item) in container.slots) {
slots[slot]?.let {
ItemElement(hudRenderer, it.size, item).render(offset + it.start, z, consumer)
}
}
return 2
}
override fun forceSilentApply() {
cacheUpToDate = false
}
}

View File

@ -0,0 +1,58 @@
package de.bixilon.minosoft.gui.rendering.gui.elements.items
import de.bixilon.minosoft.data.inventory.ItemStack
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.VerticalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.VerticalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.decide
import glm_.vec2.Vec2i
class ItemElement(
hudRenderer: HUDRenderer,
size: Vec2i,
val item: ItemStack,
) : Element(hudRenderer), Pollable {
private var count = -1
private var countText = TextElement(hudRenderer, "", background = false, noBorder = true)
init {
_size = size
forceApply()
}
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
val size = size
val countSize = countText.size
countText.render(offset + Vec2i(HorizontalAlignments.RIGHT.getOffset(size.x, countSize.x), VerticalAlignments.BOTTOM.getOffset(size.y, countSize.y)), z + 1, consumer)
return 2
}
override fun poll(): Boolean {
val count = item.count
if (this.count != count) {
this.count = count
return true
}
return false
}
override fun forceSilentApply() {
countText.text = when {
count < 0 -> TextComponent((count < -99).decide({ "-∞" }, { count }), color = ChatColors.RED) // No clue why I do this...
count == 0 -> TextComponent("0", color = ChatColors.YELLOW)
count > ProtocolDefinition.ITEM_STACK_MAX_SIZE -> TextComponent((count > 99).decide({ "" }, { count }), color = ChatColors.RED)
else -> TextComponent(count)
}
}
}

View File

@ -27,6 +27,7 @@ import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.util.vec.Vec2Util.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.Vec4Util.offset
import de.bixilon.minosoft.util.KUtil.decide
import glm_.vec2.Vec2i
open class TextElement(
@ -35,9 +36,23 @@ open class TextElement(
override var fontAlignment: HorizontalAlignments = HorizontalAlignments.LEFT,
var background: Boolean = true,
var backgroundColor: RGBColor = RenderConstants.TEXT_BACKGROUND_COLOR,
noBorder: Boolean = false,
parent: Element? = null,
) : LabeledElement(hudRenderer) {
var renderInfo = TextRenderInfo()
lateinit var renderInfo: TextRenderInfo
private set
var noBorder: Boolean = noBorder
@Synchronized set(value) {
field = value
charHeight = value.decide(Font.CHAR_HEIGHT, Font.TOTAL_CHAR_HEIGHT)
charMargin = value.decide(0, Font.CHAR_MARGIN)
forceApply()
}
var charHeight: Int = 0
private set
var charMargin: Int = 0
private set
override var text: Any = text
set(value) {
@ -53,7 +68,12 @@ open class TextElement(
emptyMessage = value.message.isEmpty()
val prefSize = Vec2i.EMPTY
if (!emptyMessage) {
ChatComponentRenderer.render(Vec2i.EMPTY, Vec2i.EMPTY, prefSize, 0, InfiniteSizeElement(hudRenderer), fontAlignment, renderWindow, null, TextRenderInfo(), value)
val renderInfo = TextRenderInfo(
fontAlignment = fontAlignment,
charHeight = charHeight,
charMargin = charMargin,
)
ChatComponentRenderer.render(Vec2i.EMPTY, Vec2i.EMPTY, prefSize, 0, InfiniteSizeElement(hudRenderer), renderWindow, null, renderInfo, value)
}
_prefSize = prefSize
forceApply()
@ -62,6 +82,7 @@ open class TextElement(
init {
this.parent = parent
this.textComponent = ChatComponent.of(text)
this.noBorder = noBorder
}
override fun forceSilentApply() {
@ -71,8 +92,12 @@ open class TextElement(
var b = 1
}
if (!emptyMessage) {
val renderInfo = TextRenderInfo()
ChatComponentRenderer.render(Vec2i.EMPTY, Vec2i.EMPTY, size, 0, this, fontAlignment, renderWindow, null, renderInfo, textComponent)
val renderInfo = TextRenderInfo(
fontAlignment = fontAlignment,
charHeight = charHeight,
charMargin = charMargin,
)
ChatComponentRenderer.render(Vec2i.EMPTY, Vec2i.EMPTY, size, 0, this, renderWindow, null, renderInfo, textComponent)
renderInfo.currentLineNumber = 0
this.renderInfo = renderInfo
}
@ -89,13 +114,13 @@ open class TextElement(
}
val initialOffset = offset + margin.offset
ChatComponentRenderer.render(initialOffset, Vec2i(initialOffset), Vec2i.EMPTY, z + 1, this, fontAlignment, renderWindow, consumer, renderInfo, textComponent)
ChatComponentRenderer.render(initialOffset, Vec2i(initialOffset), Vec2i.EMPTY, z + 1, this, renderWindow, consumer, renderInfo, textComponent)
renderInfo.currentLineNumber = 0
if (background) {
for ((line, info) in renderInfo.lines.withIndex()) {
val start = initialOffset + Vec2i(fontAlignment.getOffset(size.x, info.width), line * Font.TOTAL_CHAR_HEIGHT)
consumer.addQuad(start, start + Vec2i(info.width + Font.CHAR_MARGIN, Font.TOTAL_CHAR_HEIGHT), z, renderWindow.WHITE_TEXTURE, backgroundColor)
val start = initialOffset + Vec2i(fontAlignment.getOffset(size.x, info.width), line * charHeight)
consumer.addQuad(start, start + Vec2i(info.width + charMargin, charHeight), z, renderWindow.WHITE_TEXTURE, backgroundColor)
}
}

View File

@ -13,8 +13,10 @@
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar
import de.bixilon.minosoft.data.registries.other.containers.PlayerInventory
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.items.ContainerItemsElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
@ -26,6 +28,8 @@ class HotbarBaseElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Pollab
private val base = ImageElement(hudRenderer, baseAtlasElement)
private val frame = ImageElement(hudRenderer, hudRenderer.atlasManager[FRAME]!!, size = Vec2i(FRAME_SIZE))
private val inventoryElement = ContainerItemsElement(hudRenderer, hudRenderer.connection.player.inventory, baseAtlasElement.slots)
private var selectedSlot = 0
init {
@ -36,10 +40,12 @@ class HotbarBaseElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Pollab
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
base.render(offset + HORIZONTAL_MARGIN, z, consumer)
baseAtlasElement.slots[selectedSlot]?.let {
frame.render(offset + it.start - HORIZONTAL_MARGIN + FRAME_OFFSET, z + 1, consumer)
baseAtlasElement.slots[selectedSlot + PlayerInventory.HOTBAR_OFFSET]?.let {
frame.render(offset + it.start - HORIZONTAL_MARGIN + FRAME_OFFSET, z + 2, consumer)
}
inventoryElement.render(offset, z, consumer)
// ToDo: Item rendering
return 2 // bar + frame

View File

@ -5,39 +5,39 @@
"start": [0, 0],
"end": [182, 22],
"slots": {
"0": {
"36": {
"start": [3, 3],
"end": [19, 19]
},
"1": {
"37": {
"start": [23, 3],
"end": [39, 19]
},
"2": {
"38": {
"start": [43, 3],
"end": [59, 19]
},
"3": {
"39": {
"start": [63, 3],
"end": [79, 19]
},
"4": {
"40": {
"start": [83, 3],
"end": [99, 19]
},
"5": {
"41": {
"start": [103, 3],
"end": [119, 19]
},
"6": {
"42": {
"start": [123, 3],
"end": [139, 19]
},
"7": {
"43": {
"start": [143, 3],
"end": [159, 19]
},
"8": {
"44": {
"start": [163, 3],
"end": [179, 19]
}