mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-10 16:01:50 -04:00
hud: improve memory usage
* Every HUDElement has its own mesh now * Reuse existing mesh data (don't allocate new memory) * Use Mesh data as cache for layouted elements (not a separate float array)
This commit is contained in:
parent
e2f4170bb8
commit
fc2b5a8502
@ -15,10 +15,10 @@ package de.bixilon.minosoft.gui.rendering.gui.elements
|
|||||||
|
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
||||||
|
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.GUIMeshCache
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
||||||
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
|
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isGreater
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isGreater
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isSmaller
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isSmaller
|
||||||
@ -26,6 +26,7 @@ import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.max
|
|||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.min
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.min
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4iUtil.EMPTY
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4iUtil.EMPTY
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4iUtil.spaceSize
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4iUtil.spaceSize
|
||||||
|
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
|
||||||
import glm_.vec2.Vec2i
|
import glm_.vec2.Vec2i
|
||||||
import glm_.vec4.Vec4i
|
import glm_.vec4.Vec4i
|
||||||
|
|
||||||
@ -41,7 +42,9 @@ abstract class Element(val hudRenderer: HUDRenderer) {
|
|||||||
_parent = value
|
_parent = value
|
||||||
silentApply()
|
silentApply()
|
||||||
}
|
}
|
||||||
protected var cache = GUIMeshCache(hudRenderer.matrix, Mesh.TRIANGLE_TO_QUAD_ORDER, 0)
|
|
||||||
|
@Deprecated("Warning: Should not be directly accessed!")
|
||||||
|
val cache = GUIMeshCache(hudRenderer.matrix, renderWindow.renderSystem.primitiveMeshOrder, 1000)
|
||||||
open var cacheEnabled: Boolean = true
|
open var cacheEnabled: Boolean = true
|
||||||
open var initialCacheSize: Int = 100
|
open var initialCacheSize: Int = 100
|
||||||
open var cacheUpToDate: Boolean = false
|
open var cacheUpToDate: Boolean = false
|
||||||
@ -123,21 +126,36 @@ abstract class Element(val hudRenderer: HUDRenderer) {
|
|||||||
*/
|
*/
|
||||||
fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
|
fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
|
||||||
val offset = Vec2i(offset)
|
val offset = Vec2i(offset)
|
||||||
|
var directRendering = false
|
||||||
|
if (consumer is GUIMesh && consumer.data == cache.data) {
|
||||||
|
directRendering = true
|
||||||
|
}
|
||||||
if (RenderConstants.DISABLE_GUI_CACHE || !cacheEnabled) {
|
if (RenderConstants.DISABLE_GUI_CACHE || !cacheEnabled) {
|
||||||
return forceRender(offset, z, consumer, options)
|
if (directRendering) {
|
||||||
|
cache.clear()
|
||||||
|
}
|
||||||
|
val maxZ = forceRender(offset, z, consumer, options)
|
||||||
|
if (directRendering) {
|
||||||
|
cache.revision++
|
||||||
|
}
|
||||||
|
return maxZ
|
||||||
}
|
}
|
||||||
if (!cacheUpToDate || cache.offset != offset || hudRenderer.matrixChange || cache.matrix !== hudRenderer.matrix || z != cache.z) {
|
if (!cacheUpToDate || cache.offset != offset || hudRenderer.matrixChange || cache.matrix !== hudRenderer.matrix || z != cache.z) {
|
||||||
val cache = GUIMeshCache(hudRenderer.matrix, renderWindow.renderSystem.primitiveMeshOrder)
|
this.cache.clear()
|
||||||
|
cache.matrix = hudRenderer.matrix
|
||||||
cache.offset = Vec2i(offset)
|
cache.offset = Vec2i(offset)
|
||||||
cache.z = z
|
cache.z = z
|
||||||
val maxZ = forceRender(offset, z, cache, options)
|
val maxZ = forceRender(offset, z, cache, options)
|
||||||
cache.maxZ = maxZ
|
cache.maxZ = maxZ
|
||||||
|
if (cache.data !is DirectArrayFloatList) {
|
||||||
|
// raw mesh data
|
||||||
cache.data.finish()
|
cache.data.finish()
|
||||||
this.cache = cache
|
}
|
||||||
cacheUpToDate = true
|
cacheUpToDate = true
|
||||||
}
|
}
|
||||||
|
if (!directRendering) {
|
||||||
consumer.addCache(cache)
|
consumer.addCache(cache)
|
||||||
|
}
|
||||||
return cache.maxZ
|
return cache.maxZ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ import de.bixilon.minosoft.gui.rendering.gui.hud.elements.other.WorldInfoHUDElem
|
|||||||
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard.ScoreboardHUDElement
|
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard.ScoreboardHUDElement
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab.TabListHUDElement
|
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab.TabListHUDElement
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.title.TitleHUDElement
|
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.title.TitleHUDElement
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
|
|
||||||
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
|
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.IntegratedBufferTypes
|
import de.bixilon.minosoft.gui.rendering.system.base.IntegratedBufferTypes
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
|
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
|
||||||
@ -49,7 +48,6 @@ import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
|
|||||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
|
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
|
||||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||||
import de.bixilon.minosoft.util.collections.DirectArrayFloatList
|
|
||||||
import glm_.glm
|
import glm_.glm
|
||||||
import glm_.mat4x4.Mat4
|
import glm_.mat4x4.Mat4
|
||||||
import glm_.vec2.Vec2
|
import glm_.vec2.Vec2
|
||||||
@ -61,7 +59,6 @@ class HUDRenderer(
|
|||||||
) : Renderer, OtherDrawable {
|
) : Renderer, OtherDrawable {
|
||||||
override val renderSystem: RenderSystem = renderWindow.renderSystem
|
override val renderSystem: RenderSystem = renderWindow.renderSystem
|
||||||
val shader = renderWindow.renderSystem.createShader("minosoft:hud".toResourceLocation())
|
val shader = renderWindow.renderSystem.createShader("minosoft:hud".toResourceLocation())
|
||||||
private lateinit var mesh: GUIMesh
|
|
||||||
var scaledSize: Vec2i = renderWindow.window.size
|
var scaledSize: Vec2i = renderWindow.window.size
|
||||||
var matrix: Mat4 = Mat4()
|
var matrix: Mat4 = Mat4()
|
||||||
private var enabled = true
|
private var enabled = true
|
||||||
@ -144,6 +141,9 @@ class HUDRenderer(
|
|||||||
|
|
||||||
for (element in this.hudElements.toSynchronizedMap().values) {
|
for (element in this.hudElements.toSynchronizedMap().values) {
|
||||||
element.postInit()
|
element.postInit()
|
||||||
|
if (element is LayoutedHUDElement<*>) {
|
||||||
|
element.initMesh()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,15 +154,6 @@ class HUDRenderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun drawOther() {
|
override fun drawOther() {
|
||||||
val data = if (this::mesh.isInitialized) {
|
|
||||||
mesh.unload()
|
|
||||||
mesh.data.buffer.clear()
|
|
||||||
mesh.data
|
|
||||||
} else {
|
|
||||||
DirectArrayFloatList()
|
|
||||||
}
|
|
||||||
|
|
||||||
mesh = GUIMesh(renderWindow, matrix, data)
|
|
||||||
val hudElements = hudElements.toSynchronizedMap().values
|
val hudElements = hudElements.toSynchronizedMap().values
|
||||||
|
|
||||||
val time = System.currentTimeMillis()
|
val time = System.currentTimeMillis()
|
||||||
@ -192,13 +183,18 @@ class HUDRenderer(
|
|||||||
element.draw()
|
element.draw()
|
||||||
}
|
}
|
||||||
if (element is LayoutedHUDElement<*>) {
|
if (element is LayoutedHUDElement<*>) {
|
||||||
z += element.layout.render(element.layoutOffset, z, mesh, null)
|
z += element.prepare(z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setup()
|
setup()
|
||||||
mesh.load()
|
|
||||||
mesh.draw()
|
for (element in hudElements) {
|
||||||
|
if (element !is LayoutedHUDElement<*> || !element.enabled || element.mesh.data.isEmpty) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
element.mesh.draw()
|
||||||
|
}
|
||||||
|
|
||||||
if (matrixChange) {
|
if (matrixChange) {
|
||||||
matrixChange = false
|
matrixChange = false
|
||||||
|
@ -17,11 +17,17 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
|
|||||||
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
|
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDElement
|
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDElement
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
|
||||||
|
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
|
||||||
import glm_.vec2.Vec2i
|
import glm_.vec2.Vec2i
|
||||||
|
|
||||||
abstract class LayoutedHUDElement<T : Element>(final override val hudRenderer: HUDRenderer) : HUDElement {
|
abstract class LayoutedHUDElement<T : Element>(final override val hudRenderer: HUDRenderer) : HUDElement {
|
||||||
override val renderWindow: RenderWindow = hudRenderer.renderWindow
|
final override val renderWindow: RenderWindow = hudRenderer.renderWindow
|
||||||
override var enabled = true
|
override var enabled = true
|
||||||
|
var mesh: GUIMesh = GUIMesh(renderWindow, hudRenderer.matrix, DirectArrayFloatList(1000))
|
||||||
|
private var lastRevision = 0L
|
||||||
|
|
||||||
|
|
||||||
abstract val layout: T
|
abstract val layout: T
|
||||||
abstract val layoutOffset: Vec2i
|
abstract val layoutOffset: Vec2i
|
||||||
@ -29,4 +35,32 @@ abstract class LayoutedHUDElement<T : Element>(final override val hudRenderer: H
|
|||||||
override fun tick() {
|
override fun tick() {
|
||||||
layout.tick()
|
layout.tick()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createNewMesh() {
|
||||||
|
val mesh = this.mesh
|
||||||
|
if (mesh.state == Mesh.MeshStates.LOADED) {
|
||||||
|
mesh.unload()
|
||||||
|
}
|
||||||
|
this.mesh = GUIMesh(renderWindow, hudRenderer.matrix, mesh.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prepare(z: Int): Int {
|
||||||
|
val layoutOffset = layoutOffset
|
||||||
|
val usedZ = layout.render(layoutOffset, z, mesh, null)
|
||||||
|
|
||||||
|
val revision = layout.cache.revision
|
||||||
|
if (revision != lastRevision) {
|
||||||
|
createNewMesh()
|
||||||
|
this.mesh.load()
|
||||||
|
this.lastRevision = revision
|
||||||
|
}
|
||||||
|
|
||||||
|
return usedZ
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun initMesh() {
|
||||||
|
layout.cache.data = mesh.data
|
||||||
|
mesh.load()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
|
|||||||
import de.bixilon.minosoft.gui.rendering.input.camera.hit.EntityRaycastHit
|
import de.bixilon.minosoft.gui.rendering.input.camera.hit.EntityRaycastHit
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.BlendingFunctions
|
import de.bixilon.minosoft.gui.rendering.system.base.BlendingFunctions
|
||||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||||
import de.bixilon.minosoft.util.collections.DirectArrayFloatList
|
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
|
||||||
|
|
||||||
class CrosshairHUDElement(hudRenderer: HUDRenderer) : CustomHUDElement(hudRenderer) {
|
class CrosshairHUDElement(hudRenderer: HUDRenderer) : CustomHUDElement(hudRenderer) {
|
||||||
private lateinit var crosshairAtlasElement: HUDAtlasElement
|
private lateinit var crosshairAtlasElement: HUDAtlasElement
|
||||||
|
@ -19,7 +19,7 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
|
|||||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
||||||
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
|
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
|
||||||
import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct
|
import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct
|
||||||
import de.bixilon.minosoft.util.collections.DirectArrayFloatList
|
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
|
||||||
import glm_.mat4x4.Mat4
|
import glm_.mat4x4.Mat4
|
||||||
import glm_.vec2.Vec2
|
import glm_.vec2.Vec2
|
||||||
import glm_.vec2.Vec2t
|
import glm_.vec2.Vec2t
|
||||||
|
@ -16,27 +16,39 @@ package de.bixilon.minosoft.gui.rendering.gui.mesh
|
|||||||
import de.bixilon.minosoft.data.text.RGBColor
|
import de.bixilon.minosoft.data.text.RGBColor
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
|
||||||
import de.bixilon.minosoft.util.collections.ArrayFloatList
|
import de.bixilon.minosoft.util.collections.floats.AbstractFloatList
|
||||||
|
import de.bixilon.minosoft.util.collections.floats.HeapArrayFloatList
|
||||||
import glm_.mat4x4.Mat4
|
import glm_.mat4x4.Mat4
|
||||||
import glm_.vec2.Vec2
|
import glm_.vec2.Vec2
|
||||||
import glm_.vec2.Vec2i
|
import glm_.vec2.Vec2i
|
||||||
import glm_.vec2.Vec2t
|
import glm_.vec2.Vec2t
|
||||||
|
|
||||||
class GUIMeshCache(
|
class GUIMeshCache(
|
||||||
val matrix: Mat4,
|
var matrix: Mat4,
|
||||||
override val order: Array<Pair<Int, Int>>,
|
override val order: Array<Pair<Int, Int>>,
|
||||||
initialCacheSize: Int = 1000,
|
initialCacheSize: Int = 1000,
|
||||||
|
var data: AbstractFloatList = HeapArrayFloatList(initialCacheSize),
|
||||||
) : GUIVertexConsumer {
|
) : GUIVertexConsumer {
|
||||||
val data: ArrayFloatList = ArrayFloatList(initialCacheSize)
|
var revision: Long = 0
|
||||||
var offset: Vec2i = Vec2i.EMPTY
|
var offset: Vec2i = Vec2i.EMPTY
|
||||||
var z: Int = 0
|
var z: Int = 0
|
||||||
var maxZ: Int = 0
|
var maxZ: Int = 0
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
if (data.finished) {
|
||||||
|
data = HeapArrayFloatList(initialSize = data.size)
|
||||||
|
} else {
|
||||||
|
data.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun addVertex(position: Vec2t<*>, z: Int, texture: AbstractTexture, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) {
|
override fun addVertex(position: Vec2t<*>, z: Int, texture: AbstractTexture, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) {
|
||||||
data.addAll(GUIMesh.createVertex(matrix, position, z, texture, uv, tint, options))
|
data.addAll(GUIMesh.createVertex(matrix, position, z, texture, uv, tint, options))
|
||||||
|
revision++
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addCache(cache: GUIMeshCache) {
|
override fun addCache(cache: GUIMeshCache) {
|
||||||
data.addAll(cache.data)
|
data.addAll(cache.data)
|
||||||
|
revision++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,13 @@ class FloatOpenGLVertexBuffer(override val structure: MeshStruct, data: FloatBuf
|
|||||||
glBindVertexArray(vao)
|
glBindVertexArray(vao)
|
||||||
|
|
||||||
bind()
|
bind()
|
||||||
|
val previousLimit = buffer.limit()
|
||||||
|
val previousPosition = buffer.position()
|
||||||
buffer.limit(buffer.position())
|
buffer.limit(buffer.position())
|
||||||
buffer.flip()
|
buffer.flip()
|
||||||
glBufferData(type.gl, buffer, drawTypes.gl)
|
glBufferData(type.gl, buffer, drawTypes.gl)
|
||||||
|
buffer.limit(previousLimit)
|
||||||
|
buffer.position(previousPosition)
|
||||||
state = RenderBufferStates.UPLOADED
|
state = RenderBufferStates.UPLOADED
|
||||||
|
|
||||||
_data = null
|
_data = null
|
||||||
|
@ -16,7 +16,7 @@ package de.bixilon.minosoft.gui.rendering.util.mesh
|
|||||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.FloatVertexBuffer
|
import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.FloatVertexBuffer
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.PrimitiveTypes
|
import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.PrimitiveTypes
|
||||||
import de.bixilon.minosoft.util.collections.DirectArrayFloatList
|
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
|
||||||
import glm_.vec2.Vec2
|
import glm_.vec2.Vec2
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
@ -53,6 +53,7 @@ abstract class Mesh(
|
|||||||
_data = null
|
_data = null
|
||||||
}
|
}
|
||||||
vertices = buffer.vertices
|
vertices = buffer.vertices
|
||||||
|
state = MeshStates.LOADED
|
||||||
}
|
}
|
||||||
|
|
||||||
fun draw() {
|
fun draw() {
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package de.bixilon.minosoft.util.collections
|
||||||
|
|
||||||
|
abstract class AbstractPrimitiveList<T> : Clearable {
|
||||||
|
var finished: Boolean = false
|
||||||
|
protected set
|
||||||
|
abstract val limit: Int
|
||||||
|
abstract val size: Int
|
||||||
|
abstract val isEmpty: Boolean
|
||||||
|
|
||||||
|
protected abstract fun ensureSize(needed: Int)
|
||||||
|
abstract fun add(value: T)
|
||||||
|
|
||||||
|
abstract fun finish()
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package de.bixilon.minosoft.util.collections.floats
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.util.collections.AbstractPrimitiveList
|
||||||
|
|
||||||
|
abstract class AbstractFloatList : AbstractPrimitiveList<Float>() {
|
||||||
|
|
||||||
|
abstract fun addAll(floats: FloatArray)
|
||||||
|
abstract fun addAll(floatList: AbstractFloatList)
|
||||||
|
|
||||||
|
abstract fun toArray(): FloatArray
|
||||||
|
}
|
@ -11,25 +11,24 @@
|
|||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.bixilon.minosoft.util.collections
|
package de.bixilon.minosoft.util.collections.floats
|
||||||
|
|
||||||
import de.bixilon.minosoft.util.KUtil
|
import de.bixilon.minosoft.util.KUtil
|
||||||
import org.lwjgl.system.MemoryUtil.memAllocFloat
|
import org.lwjgl.system.MemoryUtil.memAllocFloat
|
||||||
import org.lwjgl.system.MemoryUtil.memFree
|
import org.lwjgl.system.MemoryUtil.memFree
|
||||||
|
import java.nio.BufferOverflowException
|
||||||
import java.nio.FloatBuffer
|
import java.nio.FloatBuffer
|
||||||
|
|
||||||
class DirectArrayFloatList(
|
class DirectArrayFloatList(
|
||||||
initialSize: Int = DEFAULT_INITIAL_SIZE,
|
initialSize: Int = DEFAULT_INITIAL_SIZE,
|
||||||
) {
|
) : AbstractFloatList() {
|
||||||
var buffer: FloatBuffer = memAllocFloat(initialSize) // ToDo: Clear when disconnected
|
var buffer: FloatBuffer = memAllocFloat(initialSize)
|
||||||
private set
|
private set
|
||||||
var finalized: Boolean = false
|
override val limit: Int
|
||||||
private set
|
|
||||||
val capacity: Int
|
|
||||||
get() = buffer.capacity()
|
get() = buffer.capacity()
|
||||||
val size: Int
|
override val size: Int
|
||||||
get() = buffer.position()
|
get() = buffer.position()
|
||||||
val isEmpty: Boolean
|
override val isEmpty: Boolean
|
||||||
get() = size == 0
|
get() = size == 0
|
||||||
private var unloaded = false
|
private var unloaded = false
|
||||||
|
|
||||||
@ -43,17 +42,17 @@ class DirectArrayFloatList(
|
|||||||
private var outputUpToDate = false
|
private var outputUpToDate = false
|
||||||
|
|
||||||
private fun checkFinalized() {
|
private fun checkFinalized() {
|
||||||
if (finalized) {
|
if (finished) {
|
||||||
throw IllegalStateException("ArrayFloatList is already finalized!")
|
throw IllegalStateException("ArrayFloatList is already finalized!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureSize(needed: Int) {
|
override fun ensureSize(needed: Int) {
|
||||||
checkFinalized()
|
checkFinalized()
|
||||||
if (capacity - size >= needed) {
|
if (limit - size >= needed) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var newSize = capacity
|
var newSize = limit
|
||||||
while (newSize - size < needed) {
|
while (newSize - size < needed) {
|
||||||
newSize += nextGrowStep
|
newSize += nextGrowStep
|
||||||
}
|
}
|
||||||
@ -70,19 +69,26 @@ class DirectArrayFloatList(
|
|||||||
memFree(oldBuffer)
|
memFree(oldBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(float: Float) {
|
override fun add(value: Float) {
|
||||||
ensureSize(1)
|
ensureSize(1)
|
||||||
buffer.put(float)
|
buffer.put(value)
|
||||||
outputUpToDate = false
|
outputUpToDate = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addAll(floats: FloatArray) {
|
override fun addAll(floats: FloatArray) {
|
||||||
ensureSize(floats.size)
|
ensureSize(floats.size)
|
||||||
|
try {
|
||||||
buffer.put(floats)
|
buffer.put(floats)
|
||||||
|
} catch (exception: BufferOverflowException) {
|
||||||
|
ensureSize(floats.size)
|
||||||
|
|
||||||
|
exception.printStackTrace()
|
||||||
|
}
|
||||||
outputUpToDate = false
|
outputUpToDate = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addAll(floatList: DirectArrayFloatList) {
|
override fun addAll(floatList: AbstractFloatList) {
|
||||||
|
if (floatList is DirectArrayFloatList) {
|
||||||
ensureSize(floatList.size)
|
ensureSize(floatList.size)
|
||||||
if (FLOAT_PUT_METHOD == null) { // Java < 16
|
if (FLOAT_PUT_METHOD == null) { // Java < 16
|
||||||
for (i in 0 until floatList.buffer.position()) {
|
for (i in 0 until floatList.buffer.position()) {
|
||||||
@ -92,11 +98,9 @@ class DirectArrayFloatList(
|
|||||||
FLOAT_PUT_METHOD.invoke(buffer, buffer.position(), floatList.buffer, 0, floatList.buffer.position())
|
FLOAT_PUT_METHOD.invoke(buffer, buffer.position(), floatList.buffer, 0, floatList.buffer.position())
|
||||||
buffer.position(buffer.position() + floatList.buffer.position())
|
buffer.position(buffer.position() + floatList.buffer.position())
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
addAll(floatList.toArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addAll(floatList: ArrayFloatList) {
|
|
||||||
ensureSize(floatList.size)
|
|
||||||
buffer.put(floatList.toArray())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkOutputArray() {
|
private fun checkOutputArray() {
|
||||||
@ -111,7 +115,7 @@ class DirectArrayFloatList(
|
|||||||
outputUpToDate = true
|
outputUpToDate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toArray(): FloatArray {
|
override fun toArray(): FloatArray {
|
||||||
checkOutputArray()
|
checkOutputArray()
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
@ -119,12 +123,20 @@ class DirectArrayFloatList(
|
|||||||
fun unload() {
|
fun unload() {
|
||||||
check(!unloaded) { "Already unloaded!" }
|
check(!unloaded) { "Already unloaded!" }
|
||||||
unloaded = true
|
unloaded = true
|
||||||
finalized = true // Is unloaded
|
finished = true // Is unloaded
|
||||||
memFree(buffer)
|
memFree(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun finish() {
|
override fun clear() {
|
||||||
finalized = true
|
buffer.clear()
|
||||||
|
if (output.isNotEmpty()) {
|
||||||
|
output = FloatArray(0)
|
||||||
|
}
|
||||||
|
outputUpToDate = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun finish() {
|
||||||
|
finished = true
|
||||||
val oldBuffer = buffer
|
val oldBuffer = buffer
|
||||||
buffer = memAllocFloat(oldBuffer.position())
|
buffer = memAllocFloat(oldBuffer.position())
|
||||||
if (FLOAT_PUT_METHOD == null) { // Java < 16
|
if (FLOAT_PUT_METHOD == null) { // Java < 16
|
@ -10,19 +10,16 @@
|
|||||||
*
|
*
|
||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
*/
|
*/
|
||||||
package de.bixilon.minosoft.util.collections
|
package de.bixilon.minosoft.util.collections.floats
|
||||||
|
|
||||||
class ArrayFloatList(
|
class HeapArrayFloatList(
|
||||||
initialSize: Int = DEFAULT_INITIAL_SIZE,
|
initialSize: Int = DEFAULT_INITIAL_SIZE,
|
||||||
) {
|
) : AbstractFloatList() {
|
||||||
private var data: FloatArray = FloatArray(initialSize)
|
private var data: FloatArray = FloatArray(initialSize)
|
||||||
var finalized: Boolean = false
|
override val limit: Int
|
||||||
private set
|
|
||||||
val limit: Int
|
|
||||||
get() = data.size
|
get() = data.size
|
||||||
var size = 0
|
override var size = 0
|
||||||
private set
|
override val isEmpty: Boolean
|
||||||
val isEmpty: Boolean
|
|
||||||
get() = size == 0
|
get() = size == 0
|
||||||
|
|
||||||
private val nextGrowStep = when {
|
private val nextGrowStep = when {
|
||||||
@ -35,19 +32,19 @@ class ArrayFloatList(
|
|||||||
private var outputUpToDate = false
|
private var outputUpToDate = false
|
||||||
|
|
||||||
private fun checkFinalized() {
|
private fun checkFinalized() {
|
||||||
if (finalized) {
|
if (finished) {
|
||||||
throw IllegalStateException("ArrayFloatList is already finalized!")
|
throw IllegalStateException("ArrayFloatList is already finalized!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clear() {
|
override fun clear() {
|
||||||
checkFinalized()
|
checkFinalized()
|
||||||
size = 0
|
size = 0
|
||||||
outputUpToDate = false
|
outputUpToDate = false
|
||||||
output = FloatArray(0)
|
output = FloatArray(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureSize(needed: Int) {
|
override fun ensureSize(needed: Int) {
|
||||||
checkFinalized()
|
checkFinalized()
|
||||||
if (limit - size >= needed) {
|
if (limit - size >= needed) {
|
||||||
return
|
return
|
||||||
@ -61,26 +58,30 @@ class ArrayFloatList(
|
|||||||
System.arraycopy(oldData, 0, data, 0, oldData.size)
|
System.arraycopy(oldData, 0, data, 0, oldData.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(float: Float) {
|
override fun add(value: Float) {
|
||||||
ensureSize(1)
|
ensureSize(1)
|
||||||
data[size++] = float
|
data[size++] = value
|
||||||
outputUpToDate = false
|
outputUpToDate = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addAll(floats: FloatArray) {
|
override fun addAll(floats: FloatArray) {
|
||||||
ensureSize(floats.size)
|
ensureSize(floats.size)
|
||||||
System.arraycopy(floats, 0, data, size, floats.size)
|
System.arraycopy(floats, 0, data, size, floats.size)
|
||||||
size += floats.size
|
size += floats.size
|
||||||
outputUpToDate = false
|
outputUpToDate = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addAll(floatList: ArrayFloatList) {
|
override fun addAll(floatList: AbstractFloatList) {
|
||||||
ensureSize(floatList.size)
|
ensureSize(floatList.size)
|
||||||
val source = if (floatList.finalized) {
|
val source: FloatArray = if (floatList is HeapArrayFloatList) {
|
||||||
|
if (floatList.finished) {
|
||||||
floatList.output
|
floatList.output
|
||||||
} else {
|
} else {
|
||||||
floatList.data
|
floatList.data
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
floatList.toArray()
|
||||||
|
}
|
||||||
System.arraycopy(source, 0, data, size, floatList.size)
|
System.arraycopy(source, 0, data, size, floatList.size)
|
||||||
size += floatList.size
|
size += floatList.size
|
||||||
}
|
}
|
||||||
@ -94,13 +95,13 @@ class ArrayFloatList(
|
|||||||
outputUpToDate = true
|
outputUpToDate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toArray(): FloatArray {
|
override fun toArray(): FloatArray {
|
||||||
checkOutputArray()
|
checkOutputArray()
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
fun finish() {
|
override fun finish() {
|
||||||
finalized = true
|
finished = true
|
||||||
checkOutputArray()
|
checkOutputArray()
|
||||||
data = FloatArray(0)
|
data = FloatArray(0)
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user