wip hud cache

This commit is contained in:
Bixilon 2021-09-24 15:40:54 +02:00
parent a17106db8d
commit efa9adfc97
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
19 changed files with 82 additions and 93 deletions

View File

@ -31,7 +31,9 @@ abstract class Element(val hudRenderer: HUDRenderer) {
field = value
onParentChange()
}
protected var cache = GUIMeshCache(hudRenderer.matrix)
protected var cache = GUIMeshCache(hudRenderer.matrix, 0)
open var cacheEnabled: Boolean = true
open var initialCacheSize: Int = 100
open var cacheUpToDate: Boolean = false
/**
@ -86,11 +88,33 @@ abstract class Element(val hudRenderer: HUDRenderer) {
}
/**
* Renders the element to a vertex consumer
* Renders the element (eventually from a cache) to a vertex consumer
*
* @return The number of z layers used
*/
abstract fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int
fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
if (!cacheEnabled) {
return forceRender(offset, z, consumer)
}
if (!cacheUpToDate || cache.offset != offset || hudRenderer.matrixChange || cache.matrix != hudRenderer.matrix || z != cache.z) {
val cache = GUIMeshCache(hudRenderer.matrix)
cache.offset = offset
cache.z = z
val maxZ = forceRender(offset, z, cache)
cache.maxZ = maxZ
cacheUpToDate = true
}
consumer.addCache(cache)
return cache.maxZ
}
/**
* Force renders the element to the cache/vertex consumer
*
* @return The number of z layers used
*/
abstract fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int
/**
* Applied all changes made to any property, but does not notify the parent about the change

View File

@ -31,7 +31,7 @@ class InfiniteSizeElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
get() = Vec2i.MAX
set(value) {}
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
error("Can not render InfiniteSizeElement")
}

View File

@ -42,6 +42,8 @@ open class RowLayout(
private var _prefSize = Vec2i.EMPTY
private val children: MutableList<Element> = synchronizedListOf()
override var cacheEnabled: Boolean = false // ToDo: Cache
override var prefSize: Vec2i
get() = _prefSize
set(value) {}
@ -56,7 +58,7 @@ open class RowLayout(
children.clear()
}
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
var childYOffset = 0
var maxZ = 0

View File

@ -26,8 +26,9 @@ import glm_.vec2.Vec2i
class ZLayout(hudRenderer: HUDRenderer) : Element(hudRenderer) {
private val children: MutableList<Element> = synchronizedListOf()
override var cacheEnabled: Boolean = false // ToDo: Cache
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
var zOffset = 0
for (child in children.toSynchronizedList()) {
zOffset += child.render(margin.offset + offset, z + zOffset, consumer)

View File

@ -27,6 +27,9 @@ class GridCell(
override var parent: Element?,
) : Element(hudRenderer) {
override var cacheUpToDate: Boolean by child::cacheUpToDate
override var cacheEnabled: Boolean by child::cacheEnabled
override var initialCacheSize: Int by child::initialCacheSize
override var prefMaxSize: Vec2i by child::prefMaxSize
override var size: Vec2i by child::size
override var margin: Vec4i by child::margin
override var prefSize: Vec2i by child::prefSize
@ -49,7 +52,7 @@ class GridCell(
child.parent = this
}
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
return child.render(offset, z, consumer)
}

View File

@ -30,6 +30,8 @@ class GridLayout(hudRenderer: HUDRenderer, val grid: Vec2i) : Element(hudRendere
private var columnStart = IntArray(grid.x)
private var rowStart = IntArray(grid.y)
override var cacheEnabled: Boolean = false // ToDo: Cache
operator fun set(position: Vec2i, element: Element) = add(position, element)
fun add(position: Vec2i, element: Element) {
@ -123,7 +125,7 @@ class GridLayout(hudRenderer: HUDRenderer, val grid: Vec2i) : Element(hudRendere
}
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
var maxZ = 0
for (x in 0 until grid.x) {
for (y in 0 until grid.y) {

View File

@ -19,11 +19,9 @@ 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.TextureLike
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMeshCache
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.util.vec.Vec2Util.EMPTY
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
@ -35,6 +33,7 @@ open class ImageElement(
size: Vec2i = texture.size,
tint: RGBColor = ChatColors.WHITE,
) : Element(hudRenderer) {
override var initialCacheSize: Int = GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6
var texture: AbstractTexture = texture
set(value) {
field = value
@ -70,10 +69,6 @@ open class ImageElement(
cacheUpToDate = false
}
private var matrix: Mat4 = hudRenderer.matrix
private var lastOffset: Vec2i = Vec2i(-1, -1)
init {
this.size = size
}
@ -82,20 +77,8 @@ open class ImageElement(
constructor(hudRenderer: HUDRenderer, texture: AbstractTexture, uvStart: Vec2i, uvEnd: Vec2i, size: Vec2i = texture.size, tint: RGBColor = ChatColors.WHITE) : this(hudRenderer, texture, Vec2(uvStart) * texture.singlePixelSize, Vec2(uvEnd) * texture.singlePixelSize, size, tint)
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
val matrix = hudRenderer.matrix
if (offset == lastOffset && matrix == this.matrix && cacheUpToDate) {
consumer.addCache(cache)
return 1
}
val cache = GUIMeshCache(matrix, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6)
cache.addQuad(offset, offset + size, z, texture, uvStart, uvEnd, tint)
this.lastOffset = offset
this.matrix = matrix
this.cache = cache
this.cacheUpToDate = true
consumer.addCache(cache)
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
consumer.addQuad(offset, offset + size, z, texture, uvStart, uvEnd, tint)
return 1
}

View File

@ -20,7 +20,7 @@ import glm_.vec2.Vec2i
open class SpacerElement(hudRenderer: HUDRenderer, override var size: Vec2i) : Element(hudRenderer) {
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int = 0
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int = 0
override fun silentApply() = Unit
override fun apply() = Unit

View File

@ -24,7 +24,6 @@ import de.bixilon.minosoft.gui.rendering.gui.elements.ElementAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.ElementAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.InfiniteSizeElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMeshCache
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
@ -38,9 +37,6 @@ open class TextElement(
var backgroundColor: RGBColor = RenderConstants.TEXT_BACKGROUND_COLOR,
parent: Element? = null,
) : LabeledElement(hudRenderer) {
private var previousOffset = Vec2i.EMPTY
private var previousMatrix = hudRenderer.matrix
private var previousMaxSize = Vec2i.EMPTY
private var preparedSize = Vec2i.EMPTY
var renderInfo = TextRenderInfo()
@ -109,18 +105,10 @@ open class TextElement(
}
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
if (emptyMessage) {
return 0
}
if (previousOffset != offset || previousMatrix != hudRenderer.matrix) {
cacheUpToDate = false
}
if (cacheUpToDate) {
consumer.addCache(cache)
return LAYERS
}
val cache = GUIMeshCache(hudRenderer.matrix)
val initialOffset = offset + margin.offset
ChatComponentRenderer.render(initialOffset, Vec2i(initialOffset), Vec2i.EMPTY, z + 1, this, fontAlignment, renderWindow, cache, renderInfo, textComponent)
@ -133,12 +121,6 @@ open class TextElement(
}
}
consumer.addCache(cache)
this.cache = cache
this.previousOffset = offset
this.previousMatrix = hudRenderer.matrix
this.cacheUpToDate = true
return LAYERS
}

View File

@ -43,9 +43,10 @@ class TextFlowElement(
get() = maxSize
set(value) {}
override var cacheEnabled: Boolean = false // ToDo: Cache
private var textSize = Vec2i.EMPTY
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
val visibleLines = visibleLines
if (visibleLines.isEmpty()) {
return 0

View File

@ -49,6 +49,8 @@ class HUDRenderer(
var scaledSize: Vec2i = renderWindow.window.size
var matrix: Mat4 = Mat4()
private var enabled = true
var matrixChange = true
private set
private val hudElements: MutableMap<ResourceLocation, HUDElement<*>> = synchronizedMapOf()
@ -88,6 +90,7 @@ class HUDRenderer(
connection.registerEvent(CallbackEventInvoker.of<ResizeWindowEvent> {
scaledSize = Vec2i(Vec2(it.size) / Minosoft.config.config.game.hud.scale)
matrix = glm.ortho(0.0f, scaledSize.x.toFloat(), scaledSize.y.toFloat(), 0.0f)
matrixChange = true
for (element in hudElements.toSynchronizedMap().values) {
element.layout?.onParentChange()
@ -159,6 +162,10 @@ class HUDRenderer(
shader.use()
mesh.draw()
if (matrixChange) {
matrixChange = false
}
}
operator fun <T : HUDElement<*>> get(hudBuilder: HUDBuilder<*>): T? {

View File

@ -25,7 +25,7 @@ class HotbarBaseElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
private val base = ImageElement(hudRenderer, baseAtlasElement)
private val frame = ImageElement(hudRenderer, hudRenderer.atlasManager[FRAME]!!, size = Vec2i(FRAME_SIZE))
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
base.render(offset + HORIZONTAL_MARGIN, z, consumer)
baseAtlasElement.slots[hudRenderer.connection.player.selectedHotbarSlot]?.let {
@ -37,6 +37,7 @@ class HotbarBaseElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
override fun silentApply() {
size = HOTBAR_BASE_SIZE + Vec2i(HORIZONTAL_MARGIN * 2, 1) // offset left and right; offset for the frame is just on top, not on the bottom
cacheUpToDate = false // ToDo: Check changes
}

View File

@ -33,11 +33,13 @@ class HotbarElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
hunger,
)
override var cacheEnabled: Boolean = false
init {
silentApply()
}
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
silentApply()
val initialOffset = Vec2i(offset)
var maxZ = 0

View File

@ -127,8 +127,8 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
atlasManager["minecraft:hardcore_half_frozen_heart"],
),
)
private val whiteHeartContainer = atlasManager["minecraft:white_heart_container"]
private val blackHeartContainer = atlasManager["minecraft:black_heart_container"]
private val whiteHeartContainer = atlasManager["minecraft:white_heart_container"]!!
private val blackHeartContainer = atlasManager["minecraft:black_heart_container"]!!
private var hardcode = false
private var poison = false
@ -145,10 +145,7 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
private var totalMaxHearts = 0
private var rows = 0
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
blackHeartContainer ?: return 0
whiteHeartContainer ?: return 0
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
// ToDo: Damage animation, regeneration, caching
for (heart in 0 until totalMaxHearts) {
val row = heart / HEARTS_PER_ROW
@ -213,8 +210,7 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
}
override fun silentApply() {
blackHeartContainer ?: return
whiteHeartContainer ?: return
// ToDo: Check if something changed
val player = hudRenderer.connection.player
@ -238,6 +234,7 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
}
size = Vec2i(HEARTS_PER_ROW, rows) * HEART_SIZE
cacheUpToDate = false
}

View File

@ -54,6 +54,12 @@ class HotbarHungerElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
)
)
override var cacheEnabled: Boolean
get() = super.cacheUpToDate && !animate
set(value) {
super.cacheEnabled = value
}
private var hungerEffect = false
private var animate = true
@ -65,9 +71,7 @@ class HotbarHungerElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
size = Vec2i(HUNGER_CONTAINERS, 1) * HUNGER_SIZE
}
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
// ToDo: Cache
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
var hungerLeft = hunger
var saturationLeft = saturation.toInt()
@ -123,12 +127,14 @@ class HotbarHungerElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
}
override fun silentApply() {
// ToDo: Check changes
val healthCondition = hudRenderer.connection.player.healthCondition
hunger = healthCondition.hunger
saturation = healthCondition.saturation
hungerEffect = hudRenderer.connection.player.activeStatusEffects.contains(hungerStatusEffect)
cacheUpToDate = false
}
override fun tick() {

View File

@ -1,29 +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.gui.hud.elements.scoreboard
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.mesh.GUIVertexConsumer
import glm_.vec2.Vec2i
class ScoreboardEntry(hudRenderer: HUDRenderer) : Element(hudRenderer) {
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
TODO("Not yet implemented")
}
override fun silentApply() {
TODO("Not yet implemented")
}
}

View File

@ -50,7 +50,7 @@ class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
hudRenderer.atlasManager["minecraft:tab_list_ping_5".toResourceLocation()]!!,
)
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
background.render(Vec2i(offset), z, consumer)
val size = size
@ -158,6 +158,7 @@ class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
this.size = size
background.size = size
cacheUpToDate = false
}
override fun onParentChange() {

View File

@ -73,7 +73,7 @@ class TabListEntryElement(
silentApply()
}
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
background.render(Vec2i(offset), z, consumer)
nameElement.render(Vec2i(offset), z, consumer)
pingElement.render(offset + Vec2i(ElementAlignments.RIGHT.getOffset(maxSize.x, pingElement.size.x + PADDING), PADDING), z + 1, consumer)
@ -119,6 +119,7 @@ class TabListEntryElement(
this.prefSize = Vec2i((PADDING * 2) + nameElement.prefSize.x + INNER_MARGIN + pingElement.prefSize.x, HEIGHT)
background.size = size
forcePrepare = false
cacheUpToDate = false
}
override fun onParentChange() {

View File

@ -16,9 +16,11 @@ package de.bixilon.minosoft.gui.rendering.gui.mesh
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.util.vec.Vec2Util.EMPTY
import de.bixilon.minosoft.util.collections.ArrayFloatList
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
import glm_.vec2.Vec2t
import glm_.vec4.Vec4
@ -27,6 +29,9 @@ class GUIMeshCache(
initialCacheSize: Int = 1000,
) : GUIVertexConsumer {
val data: ArrayFloatList = ArrayFloatList(initialCacheSize)
var offset: Vec2i = Vec2i.EMPTY
var z: Int = 0
var maxZ: Int = 0
override fun addVertex(position: Vec2t<*>, z: Int, texture: AbstractTexture, uv: Vec2, tint: RGBColor) {
val outPosition = matrix * Vec4(position.x.toFloat(), position.y.toFloat(), 1.0f, 1.0f)