fragmented array list

This commit is contained in:
Bixilon 2022-12-15 12:58:05 +01:00
parent d3c96e6c6e
commit 6650712158
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
30 changed files with 1184 additions and 251 deletions

View File

@ -29,8 +29,8 @@ open class ArmMesh(renderWindow: RenderWindow, primitiveType: PrimitiveTypes = r
fun addVertex(position: FloatArray, uv: Vec2) {
data.addAll(position)
data.addAll(uv.array)
data.add(position)
data.add(uv.array)
}
override fun addVertex(position: FloatArray, transformedUV: Vec2, transform: Float, textureShaderId: Float, flags: Float) {

View File

@ -30,7 +30,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.vec4.Vec4iUtil.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4iUtil.spaceSize
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
import de.bixilon.minosoft.util.collections.DirectList
abstract class Element(val guiRenderer: GUIRenderer, initialCacheSize: Int = 1000) : InputElement, DragTarget {
var ignoreDisplaySize = false
@ -168,7 +168,7 @@ abstract class Element(val guiRenderer: GUIRenderer, initialCacheSize: Int = 100
cache.offset = Vec2i(offset)
cache.options = options
forceRender(offset, cache, options)
if (cache.data !is DirectArrayFloatList) {
if (cache.data !is DirectList) {
// not raw mesh data
cache.data.finish()
}

View File

@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.gui.gui
import de.bixilon.kotlinglm.vec2.Vec2d
import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.kutil.time.TimeUtil
import de.bixilon.kutil.time.TimeUtil.millis
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
@ -33,7 +34,7 @@ import de.bixilon.minosoft.gui.rendering.renderer.drawable.Drawable
import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
import de.bixilon.minosoft.util.collections.floats.FloatListUtil
open class GUIMeshElement<T : Element>(
val element: T,
@ -41,7 +42,7 @@ open class GUIMeshElement<T : Element>(
override val guiRenderer: GUIRenderer = element.guiRenderer
override val renderWindow: RenderWindow = guiRenderer.renderWindow
private val clickCounter = MouseClickCounter()
var mesh: GUIMesh = GUIMesh(renderWindow, guiRenderer.matrix, DirectArrayFloatList(1000))
var mesh: GUIMesh = GUIMesh(renderWindow, guiRenderer.matrix, FloatListUtil.direct(1000))
override val skipDraw: Boolean
get() = if (element is BaseDrawable) element.skipDraw else false
protected var lastRevision = 0L
@ -144,7 +145,7 @@ open class GUIMeshElement<T : Element>(
val mouseAction = MouseActions[type] ?: return false
return element.onMouseAction(position, mouseButton, mouseAction, clickCounter.getClicks(mouseButton, mouseAction, position, TimeUtil.millis))
return element.onMouseAction(position, mouseButton, mouseAction, clickCounter.getClicks(mouseButton, mouseAction, position, millis()))
}
override fun onScroll(scrollOffset: Vec2d): Boolean {
@ -167,7 +168,7 @@ open class GUIMeshElement<T : Element>(
val mouseAction = MouseActions[type] ?: return null
return element.onDragMouseAction(position, mouseButton, mouseAction, clickCounter.getClicks(mouseButton, mouseAction, position, TimeUtil.millis), dragged)
return element.onDragMouseAction(position, mouseButton, mouseAction, clickCounter.getClicks(mouseButton, mouseAction, position, millis()), dragged)
}
override fun onDragScroll(scrollOffset: Vec2d, dragged: Dragged): Element? {

View File

@ -27,7 +27,7 @@ import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.system.base.BlendingFunctions
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
import de.bixilon.minosoft.util.collections.floats.BufferedArrayFloatList
class CrosshairHUDElement(guiRenderer: GUIRenderer) : CustomHUDElement(guiRenderer) {
private val profile = guiRenderer.connection.profiles.gui
@ -90,7 +90,7 @@ class CrosshairHUDElement(guiRenderer: GUIRenderer) : CustomHUDElement(guiRender
mesh?.unload()
this.mesh = null
val mesh = GUIMesh(renderWindow, guiRenderer.matrix, DirectArrayFloatList(42))
val mesh = GUIMesh(renderWindow, guiRenderer.matrix, BufferedArrayFloatList(42))
val start = (guiRenderer.scaledSize - CROSSHAIR_SIZE) / 2
mesh.addQuad(start, start + CROSSHAIR_SIZE, crosshairAtlasElement, crosshairProfile.color, null)

View File

@ -24,12 +24,11 @@ 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.vec.vec2.Vec2iUtil.orthoTimes
import de.bixilon.minosoft.util.collections.floats.AbstractFloatList
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
class GUIMesh(
renderWindow: RenderWindow,
val matrix: Mat4,
data: DirectArrayFloatList,
data: AbstractFloatList,
) : Mesh(renderWindow, GUIMeshStruct, initialCacheSize = 40000, clearOnLoad = false, data = data), GUIVertexConsumer {
override fun addVertex(position: Vec2t<*>, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) {
@ -37,7 +36,7 @@ class GUIMesh(
}
override fun addCache(cache: GUIMeshCache) {
data.addAll(cache.data)
data.add(cache.data)
}
data class GUIMeshStruct(

View File

@ -47,7 +47,7 @@ class GUIMeshCache(
}
override fun addCache(cache: GUIMeshCache) {
data.addAll(cache.data)
data.add(cache.data)
revision++
}

View File

@ -23,9 +23,9 @@ import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.PrimitiveType
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.MeshStruct
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
import de.bixilon.minosoft.util.collections.floats.AbstractFloatList
class ParticleMesh(renderWindow: RenderWindow, data: DirectArrayFloatList) : Mesh(renderWindow, ParticleMeshStruct, PrimitiveTypes.POINT, -1, clearOnLoad = false, data = data) {
class ParticleMesh(renderWindow: RenderWindow, data: AbstractFloatList) : Mesh(renderWindow, ParticleMeshStruct, PrimitiveTypes.POINT, -1, clearOnLoad = false, data = data) {
fun addVertex(position: Vec3d, scale: Float, texture: AbstractTexture, tintColor: RGBColor, uvMin: FloatArray? = null, uvMax: FloatArray? = null, light: Int) {
val minTransformedUV = if (uvMin == null) {
@ -38,8 +38,8 @@ class ParticleMesh(renderWindow: RenderWindow, data: DirectArrayFloatList) : Mes
data.add(position.x.toFloat())
data.add(position.y.toFloat())
data.add(position.z.toFloat())
data.addAll(minTransformedUV)
data.addAll(maxTransformedUV)
data.add(minTransformedUV)
data.add(maxTransformedUV)
data.add(texture.renderData.shaderTextureId.buffer())
data.add(scale)
data.add(tintColor.rgba.buffer())

View File

@ -39,7 +39,7 @@ import de.bixilon.minosoft.protocol.network.connection.play.PlayConnectionStates
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.minosoft
import de.bixilon.minosoft.util.chunk.ChunkUtil.isInViewDistance
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
import de.bixilon.minosoft.util.collections.floats.BufferedArrayFloatList
class ParticleRenderer(
@ -52,8 +52,8 @@ class ParticleRenderer(
private val translucentShader = renderSystem.createShader(minosoft("particle")) { ParticleShader(it, false) }
// There is no opaque mesh because it is simply not needed (every particle has transparency)
private var transparentMesh = ParticleMesh(renderWindow, DirectArrayFloatList(RenderConstants.MAXIMUM_PARTICLE_AMOUNT * ParticleMesh.ParticleMeshStruct.FLOATS_PER_VERTEX))
private var translucentMesh = ParticleMesh(renderWindow, DirectArrayFloatList(RenderConstants.MAXIMUM_PARTICLE_AMOUNT * ParticleMesh.ParticleMeshStruct.FLOATS_PER_VERTEX))
private var transparentMesh = ParticleMesh(renderWindow, BufferedArrayFloatList(RenderConstants.MAXIMUM_PARTICLE_AMOUNT * ParticleMesh.ParticleMeshStruct.FLOATS_PER_VERTEX))
private var translucentMesh = ParticleMesh(renderWindow, BufferedArrayFloatList(RenderConstants.MAXIMUM_PARTICLE_AMOUNT * ParticleMesh.ParticleMeshStruct.FLOATS_PER_VERTEX))
private val particlesLock = SimpleLock()
private var particles: MutableList<Particle> = mutableListOf()

View File

@ -14,7 +14,6 @@
package de.bixilon.minosoft.gui.rendering.sky.box
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.system.base.MeshUtil.buffer
import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.PrimitiveTypes
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
import de.bixilon.minosoft.gui.rendering.util.mesh.PositionOnlyMeshStruct
@ -22,27 +21,28 @@ import de.bixilon.minosoft.gui.rendering.util.mesh.PositionOnlyMeshStruct
class SkyboxMesh(renderWindow: RenderWindow) : Mesh(renderWindow, PositionOnlyMeshStruct, PrimitiveTypes.TRIANGLE, initialCacheSize = 6 * 2 * 3 * PositionOnlyMeshStruct.FLOATS_PER_VERTEX) {
init {
data.addAll(floatArrayOf(
-1.0f, +1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, -1.0f,
+1.0f, +1.0f, -1.0f,
-1.0f, +1.0f, -1.0f,
data.add(
floatArrayOf(
-1.0f, +1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, -1.0f,
+1.0f, +1.0f, -1.0f,
-1.0f, +1.0f, -1.0f,
-1.0f, -1.0f, +1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, +1.0f, -1.0f,
-1.0f, +1.0f, -1.0f,
-1.0f, +1.0f, +1.0f,
-1.0f, -1.0f, +1.0f,
-1.0f, -1.0f, +1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, +1.0f, -1.0f,
-1.0f, +1.0f, -1.0f,
-1.0f, +1.0f, +1.0f,
-1.0f, -1.0f, +1.0f,
+1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, +1.0f,
+1.0f, +1.0f, +1.0f,
+1.0f, +1.0f, +1.0f,
+1.0f, +1.0f, -1.0f,
+1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, +1.0f,
+1.0f, +1.0f, +1.0f,
+1.0f, +1.0f, +1.0f,
+1.0f, +1.0f, -1.0f,
+1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, +1.0f,
-1.0f, +1.0f, +1.0f,

View File

@ -23,7 +23,7 @@ import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct
class SkyboxTextureMesh(renderWindow: RenderWindow) : Mesh(renderWindow, SkyboxTextureMeshStruct, PrimitiveTypes.TRIANGLE, initialCacheSize = 6 * 2 * 3 * SkyboxTextureMeshStruct.FLOATS_PER_VERTEX) {
init {
data.addAll(
data.add(
floatArrayOf(
-1.0f, +1.0f, -1.0f, 0.buffer(),
-1.0f, -1.0f, -1.0f, 3.buffer(),

View File

@ -25,7 +25,7 @@ import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct
class CloudMesh(renderWindow: RenderWindow) : Mesh(renderWindow, CloudMeshStruct, renderWindow.renderSystem.preferredPrimitiveType) {
fun addVertex(start: Vec3, side: Directions) {
data.addAll(start.array)
data.add(start.array)
data.add(side.ordinal.buffer())
}

View File

@ -21,7 +21,7 @@ import de.bixilon.minosoft.gui.rendering.util.mesh.PositionOnlyMeshStruct
class SunScatterMesh(renderWindow: RenderWindow) : Mesh(renderWindow, PositionOnlyMeshStruct, PrimitiveTypes.TRIANGLE, initialCacheSize = 6 * 2 * 3 * PositionOnlyMeshStruct.FLOATS_PER_VERTEX) {
init {
data.addAll(
data.add(
floatArrayOf(
-1.0f, +0.2f, -1.0f,
-1.0f, -0.2f, -1.0f,

View File

@ -29,6 +29,8 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager
import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem
import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.collections.floats.AbstractFloatList
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
import java.nio.ByteBuffer
import java.nio.FloatBuffer
@ -117,6 +119,13 @@ interface RenderSystem {
fun createNativeShader(vertex: ResourceLocation, geometry: ResourceLocation? = null, fragment: ResourceLocation): NativeShader
fun createVertexBuffer(structure: MeshStruct, data: FloatBuffer, primitiveType: PrimitiveTypes = preferredPrimitiveType): FloatVertexBuffer
fun createVertexBuffer(structure: MeshStruct, data: AbstractFloatList, primitiveType: PrimitiveTypes = preferredPrimitiveType): FloatVertexBuffer {
if (data is DirectArrayFloatList) {
return createVertexBuffer(structure, data.toBuffer(), primitiveType)
}
return createVertexBuffer(structure, FloatBuffer.wrap(data.toArray()), primitiveType)
}
fun createIntUniformBuffer(data: IntArray = IntArray(0)): IntUniformBuffer
fun createFloatUniformBuffer(data: FloatBuffer): FloatUniformBuffer
fun createFramebuffer(): Framebuffer

View File

@ -18,8 +18,9 @@ import de.bixilon.minosoft.gui.rendering.system.base.buffer.RenderableBufferDraw
import de.bixilon.minosoft.gui.rendering.system.base.buffer.RenderableBufferStates
import de.bixilon.minosoft.gui.rendering.system.base.buffer.RenderableBufferTypes
import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem
import org.lwjgl.opengl.GL15.glBufferData
import org.lwjgl.opengl.GL15.glBufferSubData
import org.lwjgl.opengl.GL15C
import org.lwjgl.system.MemoryUtil.memAddress
import java.nio.FloatBuffer
open class FloatOpenGLBuffer(renderSystem: OpenGLRenderSystem, protected var _data: FloatBuffer?) : OpenGLRenderableBuffer(renderSystem, RenderableBufferTypes.ARRAY_BUFFER), RenderFloatBuffer {
@ -33,7 +34,7 @@ open class FloatOpenGLBuffer(renderSystem: OpenGLRenderSystem, protected var _da
override fun initialUpload() {
bind()
buffer.flip()
glBufferData(type.gl, buffer, drawTypes.gl)
nglBufferData(type.gl, buffer, drawTypes.gl)
unbind()
state = RenderableBufferStates.UPLOADED
}
@ -43,4 +44,8 @@ open class FloatOpenGLBuffer(renderSystem: OpenGLRenderSystem, protected var _da
glBufferSubData(type.gl, 0, buffer)
unbind()
}
private fun nglBufferData(target: Int, buffer: FloatBuffer, usage: Int) {
GL15C.nglBufferData(target, Integer.toUnsignedLong(buffer.remaining()) shl 2, memAddress(buffer), usage)
}
}

View File

@ -15,10 +15,13 @@ package de.bixilon.minosoft.gui.rendering.util.mesh
import de.bixilon.kotlinglm.vec2.Vec2
import de.bixilon.kotlinglm.vec3.Vec3
import de.bixilon.kutil.cast.CastUtil.unsafeCast
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.PrimitiveTypes
import de.bixilon.minosoft.util.collections.floats.AbstractFloatList
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
import de.bixilon.minosoft.util.collections.floats.FloatListUtil
abstract class Mesh(
val renderWindow: RenderWindow,
@ -26,18 +29,18 @@ abstract class Mesh(
private val primitiveType: PrimitiveTypes = renderWindow.renderSystem.preferredPrimitiveType,
var initialCacheSize: Int = 10000,
val clearOnLoad: Boolean = true,
data: DirectArrayFloatList? = null,
data: AbstractFloatList? = null,
val onDemand: Boolean = false,
) : AbstractVertexConsumer {
override val order = renderWindow.renderSystem.primitiveMeshOrder
val reversedOrder = order.reversedArray()
private var _data: DirectArrayFloatList? = data ?: if (onDemand) null else DirectArrayFloatList(initialCacheSize)
var data: DirectArrayFloatList
private var _data: AbstractFloatList? = data ?: if (onDemand) null else FloatListUtil.direct(initialCacheSize)
var data: AbstractFloatList
get() {
if (_data == null && onDemand) {
_data = DirectArrayFloatList(initialCacheSize)
_data = FloatListUtil.direct(initialCacheSize)
}
return _data as DirectArrayFloatList
return _data.unsafeCast()
}
set(value) {
_data = value
@ -53,10 +56,13 @@ abstract class Mesh(
fun load() {
buffer = renderWindow.renderSystem.createVertexBuffer(struct, data.buffer, primitiveType)
val data = this.data
buffer = renderWindow.renderSystem.createVertexBuffer(struct, data, primitiveType)
buffer.init()
if (clearOnLoad) {
data.unload()
if (data is DirectArrayFloatList) {
data.unload()
}
_data = null
}
vertices = buffer.vertices

View File

@ -23,27 +23,28 @@ import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct
class WorldBorderMesh(renderWindow: RenderWindow) : Mesh(renderWindow, WorldBorderMeshStruct, PrimitiveTypes.TRIANGLE, initialCacheSize = 6 * 2 * 3 * WorldBorderMeshStruct.FLOATS_PER_VERTEX) {
init {
data.addAll(floatArrayOf(
-1.0f, +1.0f, -1.0f, 1.buffer(),
+1.0f, -1.0f, -1.0f, 0.buffer(),
-1.0f, -1.0f, -1.0f, 3.buffer(),
+1.0f, -1.0f, -1.0f, 0.buffer(),
-1.0f, +1.0f, -1.0f, 1.buffer(),
+1.0f, +1.0f, -1.0f, 2.buffer(),
data.add(
floatArrayOf(
-1.0f, +1.0f, -1.0f, 1.buffer(),
+1.0f, -1.0f, -1.0f, 0.buffer(),
-1.0f, -1.0f, -1.0f, 3.buffer(),
+1.0f, -1.0f, -1.0f, 0.buffer(),
-1.0f, +1.0f, -1.0f, 1.buffer(),
+1.0f, +1.0f, -1.0f, 2.buffer(),
-1.0f, -1.0f, +1.0f, 3.buffer(),
-1.0f, +1.0f, -1.0f, 2.buffer(),
-1.0f, -1.0f, -1.0f, 0.buffer(),
-1.0f, +1.0f, -1.0f, 2.buffer(),
-1.0f, -1.0f, +1.0f, 3.buffer(),
-1.0f, +1.0f, +1.0f, 1.buffer(),
-1.0f, -1.0f, +1.0f, 3.buffer(),
-1.0f, +1.0f, -1.0f, 2.buffer(),
-1.0f, -1.0f, -1.0f, 0.buffer(),
-1.0f, +1.0f, -1.0f, 2.buffer(),
-1.0f, -1.0f, +1.0f, 3.buffer(),
-1.0f, +1.0f, +1.0f, 1.buffer(),
+1.0f, -1.0f, -1.0f, 3.buffer(),
+1.0f, +1.0f, +1.0f, 2.buffer(),
+1.0f, -1.0f, +1.0f, 0.buffer(),
+1.0f, +1.0f, +1.0f, 2.buffer(),
+1.0f, -1.0f, -1.0f, 3.buffer(),
+1.0f, +1.0f, -1.0f, 1.buffer(),
+1.0f, -1.0f, -1.0f, 3.buffer(),
+1.0f, +1.0f, +1.0f, 2.buffer(),
+1.0f, -1.0f, +1.0f, 0.buffer(),
+1.0f, +1.0f, +1.0f, 2.buffer(),
+1.0f, -1.0f, -1.0f, 3.buffer(),
+1.0f, +1.0f, -1.0f, 1.buffer(),
-1.0f, -1.0f, +1.0f, 0.buffer(),
+1.0f, +1.0f, +1.0f, 1.buffer(),

View File

@ -30,7 +30,7 @@ class SingleWorldMesh(renderWindow: RenderWindow, initialCacheSize: Int, onDeman
data.add(position[0])
data.add(position[1])
data.add(position[2])
data.addAll(transformedUV)
data.add(transformedUV)
data.add(texture.renderData.shaderTextureId.buffer())
data.add((tintColor or (light shl 24)).buffer())
}
@ -41,7 +41,7 @@ class SingleWorldMesh(renderWindow: RenderWindow, initialCacheSize: Int, onDeman
data.add(x)
data.add(y)
data.add(z)
data.addAll(transformedUV)
data.add(transformedUV)
data.add(shaderTextureId)
data.add(tintLight)
}

View File

@ -19,6 +19,7 @@ import de.bixilon.kotlinglm.vec3.Vec3i
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
import de.bixilon.minosoft.gui.rendering.world.entities.BlockEntityRenderer
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
class WorldMesh(
renderWindow: RenderWindow,
@ -30,7 +31,7 @@ class WorldMesh(
var opaqueMesh: SingleWorldMesh? = SingleWorldMesh(renderWindow, if (smallMesh) 1000 else 100000)
var translucentMesh: SingleWorldMesh? = SingleWorldMesh(renderWindow, if (smallMesh) 1000 else 10000)
var transparentMesh: SingleWorldMesh? = SingleWorldMesh(renderWindow, if (smallMesh) 1000 else 20000)
var textMesh: SingleWorldMesh? = SingleWorldMesh(renderWindow, if (smallMesh) 1000 else 200000, onDemand = true)
var textMesh: SingleWorldMesh? = SingleWorldMesh(renderWindow, if (smallMesh) 1000 else 50000, onDemand = true)
var blockEntities: Set<BlockEntityRenderer<*>>? = null
// used for frustum culling
@ -59,8 +60,11 @@ class WorldMesh(
if (mesh == null) {
return false
}
if (mesh.data.isEmpty) {
mesh.data.unload()
val data = mesh.data
if (data.isEmpty) {
if (data is DirectArrayFloatList) {
data.unload()
}
return true
}
meshes++

View File

@ -0,0 +1,16 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.util.collections
interface DirectList

View File

@ -14,11 +14,16 @@
package de.bixilon.minosoft.util.collections.floats
import de.bixilon.minosoft.util.collections.AbstractPrimitiveList
import java.nio.FloatBuffer
abstract class AbstractFloatList : AbstractPrimitiveList<Float>() {
abstract fun addAll(floats: FloatArray)
abstract fun addAll(floatList: AbstractFloatList)
abstract fun add(array: FloatArray)
operator fun plusAssign(array: FloatArray) = add(array)
abstract fun add(floatList: AbstractFloatList)
operator fun plusAssign(floatList: AbstractFloatList) = add(floatList)
abstract fun add(buffer: FloatBuffer)
operator fun plusAssign(buffer: FloatBuffer) = add(buffer)
abstract fun toArray(): FloatArray
}

View File

@ -0,0 +1,152 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.util.collections.floats
import de.bixilon.minosoft.util.collections.floats.FloatListUtil.copy
import de.bixilon.minosoft.util.collections.floats.FloatListUtil.finish
import org.lwjgl.system.MemoryUtil.memAllocFloat
import org.lwjgl.system.MemoryUtil.memFree
import java.nio.FloatBuffer
class BufferedArrayFloatList(
initialSize: Int = FloatListUtil.DEFAULT_INITIAL_SIZE,
) : AbstractFloatList(), DirectArrayFloatList {
var buffer: FloatBuffer = memAllocFloat(initialSize)
private set
override var limit: Int = buffer.limit()
private set
override val size: Int
get() = buffer.position()
override val isEmpty: Boolean
get() = size == 0
private var unloaded = false
private val nextGrowStep = when {
initialSize <= 0 -> FloatListUtil.DEFAULT_INITIAL_SIZE
initialSize <= 100 -> 100
else -> initialSize
}
private var output: FloatArray = FloatArray(0)
private var outputUpToDate = false
override fun ensureSize(needed: Int) {
checkFinished()
if (limit - size >= needed) {
return
}
var newSize = limit
newSize += if (nextGrowStep < needed) {
(needed / nextGrowStep + 1) * nextGrowStep
} else {
nextGrowStep
}
grow(newSize)
}
private fun grow(size: Int) {
val buffer = buffer
this.buffer = memAllocFloat(size)
limit = size
buffer.copy(this.buffer)
memFree(buffer)
}
override fun add(value: Float) {
ensureSize(1)
buffer.put(value)
invalidateOutput()
}
override fun add(array: FloatArray) {
ensureSize(array.size)
buffer.put(array)
invalidateOutput()
}
override fun add(buffer: FloatBuffer) {
ensureSize(buffer.position())
buffer.copy(this.buffer)
}
override fun add(floatList: AbstractFloatList) {
ensureSize(floatList.size)
when (floatList) {
is FragmentedArrayFloatList -> {
for (buffer in floatList.fragments) {
buffer.copy(this.buffer)
}
}
is DirectArrayFloatList -> floatList.toBuffer().copy(this.buffer)
else -> add(floatList.toArray())
}
invalidateOutput()
}
private fun checkOutputArray() {
if (outputUpToDate) {
return
}
val position = buffer.position()
output = FloatArray(position)
buffer.position(0)
buffer.get(output, 0, position)
buffer.position(position)
outputUpToDate = true
}
override fun toArray(): FloatArray {
checkOutputArray()
return output
}
override fun unload() {
check(!unloaded) { "Already unloaded!" }
unloaded = true
finished = true // Is unloaded
memFree(buffer)
}
override fun clear() {
buffer.clear()
if (output.isNotEmpty()) {
output = FloatArray(0)
}
invalidateOutput()
}
override fun finish() {
finished = true
limit = buffer.limit()
this.buffer = buffer.finish()
}
protected fun finalize() {
if (unloaded) {
return
}
memFree(buffer)
}
override fun toBuffer(): FloatBuffer {
return this.buffer
}
private fun invalidateOutput() {
if (outputUpToDate) {
outputUpToDate = false
}
}
}

View File

@ -13,159 +13,11 @@
package de.bixilon.minosoft.util.collections.floats
import de.bixilon.kutil.exception.ExceptionUtil.catchAll
import org.lwjgl.system.MemoryUtil.memAllocFloat
import org.lwjgl.system.MemoryUtil.memFree
import java.nio.BufferOverflowException
import de.bixilon.minosoft.util.collections.DirectList
import java.nio.FloatBuffer
class DirectArrayFloatList(
initialSize: Int = DEFAULT_INITIAL_SIZE,
) : AbstractFloatList() {
var buffer: FloatBuffer = memAllocFloat(initialSize)
private set
override var limit: Int = buffer.limit()
private set
override val size: Int
get() = buffer.position()
override val isEmpty: Boolean
get() = size == 0
private var unloaded = false
interface DirectArrayFloatList : DirectList {
private val nextGrowStep = when {
initialSize <= 0 -> DEFAULT_INITIAL_SIZE
initialSize <= 100 -> 100
else -> initialSize
}
private var output: FloatArray = FloatArray(0)
private var outputUpToDate = false
override fun ensureSize(needed: Int) {
checkFinished()
if (limit - size >= needed) {
return
}
var newSize = limit
newSize += if (nextGrowStep < needed) {
(needed / nextGrowStep + 1) * nextGrowStep
} else {
nextGrowStep
}
grow(newSize)
}
private fun grow(size: Int) {
val oldBuffer = buffer
buffer = memAllocFloat(size)
limit = size
if (FLOAT_PUT_METHOD == null) { // Java < 16
for (i in 0 until oldBuffer.position()) {
buffer.put(oldBuffer.get(i))
}
} else {
FLOAT_PUT_METHOD.invoke(buffer, 0, oldBuffer, 0, oldBuffer.position())
buffer.position(oldBuffer.position())
}
memFree(oldBuffer)
}
override fun add(value: Float) {
ensureSize(1)
buffer.put(value)
if (outputUpToDate) {
outputUpToDate = false
}
}
override fun addAll(floats: FloatArray) {
ensureSize(floats.size)
try {
buffer.put(floats)
} catch (exception: BufferOverflowException) {
ensureSize(floats.size)
exception.printStackTrace()
}
if (outputUpToDate) {
outputUpToDate = false
}
}
override fun addAll(floatList: AbstractFloatList) {
if (floatList is DirectArrayFloatList) {
ensureSize(floatList.size)
if (FLOAT_PUT_METHOD == null) { // Java < 16
for (i in 0 until floatList.buffer.position()) {
buffer.put(floatList.buffer.get(i))
}
} else {
FLOAT_PUT_METHOD.invoke(buffer, buffer.position(), floatList.buffer, 0, floatList.buffer.position())
buffer.position(buffer.position() + floatList.buffer.position())
}
} else {
addAll(floatList.toArray())
}
}
private fun checkOutputArray() {
if (outputUpToDate) {
return
}
val position = buffer.position()
output = FloatArray(position)
buffer.position(0)
buffer.get(output, 0, position)
buffer.position(position)
outputUpToDate = true
}
override fun toArray(): FloatArray {
checkOutputArray()
return output
}
fun unload() {
check(!unloaded) { "Already unloaded!" }
unloaded = true
finished = true // Is unloaded
memFree(buffer)
}
override fun clear() {
buffer.clear()
if (output.isNotEmpty()) {
output = FloatArray(0)
}
outputUpToDate = false
}
override fun finish() {
finished = true
val oldBuffer = buffer
buffer = memAllocFloat(oldBuffer.position())
limit = buffer.limit()
if (FLOAT_PUT_METHOD == null) { // Java < 16
for (i in 0 until oldBuffer.position()) {
buffer.put(oldBuffer.get(i))
}
} else {
FLOAT_PUT_METHOD.invoke(buffer, 0, oldBuffer, 0, oldBuffer.position())
buffer.position(buffer.limit())
}
memFree(oldBuffer)
}
protected fun finalize() {
if (unloaded) {
return
}
memFree(buffer)
}
private companion object {
private val FLOAT_PUT_METHOD = catchAll { FloatBuffer::class.java.getMethod("put", Int::class.java, FloatBuffer::class.java, Int::class.java, Int::class.java) }
private const val DEFAULT_INITIAL_SIZE = 1000
}
fun toBuffer(): FloatBuffer
fun unload()
}

View File

@ -0,0 +1,62 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.util.collections.floats
import de.bixilon.kutil.exception.ExceptionUtil
import org.lwjgl.system.MemoryUtil
import org.lwjgl.system.MemoryUtil.memAllocFloat
import java.nio.FloatBuffer
object FloatListUtil {
const val PREFER_FRAGMENTED = true
val FLOAT_PUT_METHOD = ExceptionUtil.catchAll { FloatBuffer::class.java.getMethod("put", Int::class.java, FloatBuffer::class.java, Int::class.java, Int::class.java) }
const val DEFAULT_INITIAL_SIZE = 1000
fun direct(initialSize: Int = DEFAULT_INITIAL_SIZE): AbstractFloatList {
return if (PREFER_FRAGMENTED) FragmentedArrayFloatList(initialSize) else BufferedArrayFloatList(initialSize)
}
fun FloatBuffer.finish(): FloatBuffer {
val buffer = memAllocFloat(position())
if (FLOAT_PUT_METHOD == null) { // Java < 16
for (i in 0 until position()) {
buffer.put(get(i))
}
} else {
FLOAT_PUT_METHOD.invoke(buffer, 0, this, 0, position())
buffer.position(buffer.limit())
}
MemoryUtil.memFree(this)
return buffer
}
fun FloatBuffer.copy(sourceOffset: Int, destination: FloatBuffer, destinationOffset: Int, length: Int) {
if (length == 0) {
return
}
if (FLOAT_PUT_METHOD == null) { // Java < 16
for (i in 0 until length) {
destination.put(destinationOffset + i, this.get(sourceOffset + i))
}
return
}
FLOAT_PUT_METHOD.invoke(destination, destinationOffset, this, sourceOffset, length)
destination.position(destination.position() + length)
}
fun FloatBuffer.copy(destination: FloatBuffer) {
copy(0, destination, destination.position(), position())
}
}

View File

@ -0,0 +1,231 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.util.collections.floats
import de.bixilon.minosoft.util.collections.floats.FloatListUtil.copy
import org.lwjgl.system.MemoryUtil.memAllocFloat
import org.lwjgl.system.MemoryUtil.memFree
import java.nio.FloatBuffer
class FragmentedArrayFloatList(
initialSize: Int = FloatListUtil.DEFAULT_INITIAL_SIZE,
) : AbstractFloatList(), DirectArrayFloatList {
var fragments: MutableList<FloatBuffer> = mutableListOf()
override var limit: Int = 0
private set
override var size: Int = 0
private set
override val isEmpty: Boolean
get() = size == 0
private var unloaded = false
private val nextGrowStep = when {
initialSize <= 0 -> FloatListUtil.DEFAULT_INITIAL_SIZE
initialSize <= 100 -> 100
else -> initialSize
}
private var output: FloatArray? = null
private var buffer: FloatBuffer? = null
override fun ensureSize(needed: Int) {
grow(needed)
}
private fun grow(size: Int): FloatBuffer {
checkFinished()
if (limit - this.size >= size) {
return this.fragments.last()
}
val grow = if (nextGrowStep < size) {
(size / nextGrowStep + 1) * nextGrowStep
} else {
nextGrowStep
}
return forceGrow(grow)
}
private fun forceGrow(size: Int): FloatBuffer {
val last = fragments.lastOrNull()
val buffer = memAllocFloat(size)
fragments += buffer
limit += size
return buffer
}
override fun add(value: Float) {
val buffer = grow(1)
if (buffer.position() >= buffer.limit()) {
println()
}
buffer.put(value)
size += 1
invalidateOutput()
}
override fun add(array: FloatArray) {
if (array.isEmpty()) return
invalidateOutput()
var offset = 0
size += array.size
if (fragments.isNotEmpty()) {
val fragment = fragments.last()
val remaining = fragment.limit() - fragment.position()
val copy = minOf(array.size, remaining)
fragment.put(array, 0, copy)
offset += copy
if (array.size <= remaining) {
// everything copied
return
}
}
val length = array.size - offset
val next = grow(length)
next.put(array, offset, length)
next.position(length)
}
override fun add(buffer: FloatBuffer) {
if (buffer.position() == 0) return
invalidateOutput()
var offset = 0
val position = buffer.position()
size += position
if (fragments.isNotEmpty()) {
val fragment = fragments.last()
val remaining = fragment.limit() - fragment.position()
val copy = minOf(position, remaining)
buffer.copy(0, fragment, fragment.position(), copy)
offset += copy
if (position <= remaining) {
// everything copied
return
}
}
val length = position - offset
val next = grow(length)
buffer.copy(offset, next, 0, length)
next.position(length)
}
override fun add(floatList: AbstractFloatList) {
when (floatList) {
is FragmentedArrayFloatList -> {
// TODO: add dirty method (just adding their fragments to our list of fragments)
for (buffer in floatList.fragments) {
add(buffer)
}
}
is DirectArrayFloatList -> add(floatList.toBuffer())
else -> add(floatList.toArray())
}
invalidateOutput()
}
private fun checkOutputArray(): FloatArray {
this.output?.let { return it }
val output = FloatArray(size)
var offset = 0
for (buffer in fragments) {
val position = buffer.position()
buffer.position(0)
buffer.get(output, offset, position)
offset += position
buffer.position(position)
}
this.output = output
return output
}
override fun toArray(): FloatArray {
return checkOutputArray()
}
override fun unload() {
check(!unloaded) { "Already unloaded!" }
unloaded = true
finished = true // Is unloaded
for (buffer in fragments) {
memFree(buffer)
}
this.output = null
val buffer = this.buffer
if (buffer != null) {
memFree(buffer)
this.buffer = null
}
fragments.clear()
}
override fun clear() {
size = 0
for (buffer in fragments) {
buffer.clear()
}
if (output != null) {
output = null
}
invalidateOutput()
}
override fun finish() {
finished = true
if (fragments.isEmpty()) {
return
}
val last = fragments.removeLast()
val next = memAllocFloat(last.position())
last.copy(next)
fragments += next
}
protected fun finalize() {
if (unloaded) {
return
}
for (buffer in fragments) {
memFree(buffer)
}
fragments.clear()
}
private fun invalidateOutput() {
if (this.output != null) {
this.output = null
}
if (this.buffer != null) {
this.buffer = null
}
}
override fun toBuffer(): FloatBuffer {
this.buffer?.let { return it }
if (fragments.size == 1) {
return fragments.first()
}
val buffer = memAllocFloat(size)
for (fragment in fragments) {
fragment.copy(buffer)
}
this.buffer = buffer
return buffer
}
}

View File

@ -12,8 +12,10 @@
*/
package de.bixilon.minosoft.util.collections.floats
import java.nio.FloatBuffer
class HeapArrayFloatList(
initialSize: Int = DEFAULT_INITIAL_SIZE,
initialSize: Int = FloatListUtil.DEFAULT_INITIAL_SIZE,
) : AbstractFloatList() {
private var data: FloatArray = FloatArray(initialSize)
override val limit: Int
@ -23,7 +25,7 @@ class HeapArrayFloatList(
get() = size == 0
private val nextGrowStep = when {
initialSize <= 0 -> DEFAULT_INITIAL_SIZE
initialSize <= 0 -> FloatListUtil.DEFAULT_INITIAL_SIZE
initialSize <= 50 -> 50
else -> initialSize
}
@ -40,7 +42,7 @@ class HeapArrayFloatList(
override fun clear() {
checkFinalized()
size = 0
outputUpToDate = false
invalidateOutput()
output = FloatArray(0)
}
@ -65,21 +67,27 @@ class HeapArrayFloatList(
override fun add(value: Float) {
ensureSize(1)
data[size++] = value
if (outputUpToDate) {
outputUpToDate = false
}
invalidateOutput()
}
override fun addAll(floats: FloatArray) {
ensureSize(floats.size)
System.arraycopy(floats, 0, data, size, floats.size)
size += floats.size
if (outputUpToDate) {
outputUpToDate = false
}
override fun add(array: FloatArray) {
ensureSize(array.size)
System.arraycopy(array, 0, data, size, array.size)
size += array.size
invalidateOutput()
}
override fun addAll(floatList: AbstractFloatList) {
override fun add(buffer: FloatBuffer) {
val position = buffer.position()
ensureSize(position)
for (i in 0 until position) {
data[size + i] = buffer.get(i)
}
size += position
invalidateOutput()
}
override fun add(floatList: AbstractFloatList) {
ensureSize(floatList.size)
val source: FloatArray = if (floatList is HeapArrayFloatList) {
if (floatList.finished) {
@ -92,9 +100,7 @@ class HeapArrayFloatList(
}
System.arraycopy(source, 0, data, size, floatList.size)
size += floatList.size
if (outputUpToDate) {
outputUpToDate = false
}
invalidateOutput()
}
private fun checkOutputArray() {
@ -117,8 +123,9 @@ class HeapArrayFloatList(
data = FloatArray(0)
}
private companion object {
private const val DEFAULT_INITIAL_SIZE = 1000
private fun invalidateOutput() {
if (outputUpToDate) {
outputUpToDate = false
}
}
}

View File

@ -0,0 +1,449 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.util.collections.floats
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.nio.FloatBuffer
import kotlin.test.assertContentEquals
abstract class AbstractFloatListTest {
abstract fun create(initialSize: Int = 1): AbstractFloatList
@Test
fun initialListSize() {
val list = create()
assertEquals(0, list.size)
}
@Test
fun addSingleFloat() {
val list = create()
list.add(189.0f)
assertEquals(1, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f), array)
}
@Test
fun addMultipleFloats() {
val list = create()
list.add(189.0f)
list.add(289.0f)
list.add(389.0f)
assertEquals(3, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f), array)
}
@Test
fun addVastFloats() {
val list = create()
for (i in 0 until 1000) {
list.add(i.toFloat() * 2.0f)
}
assertEquals(1000, list.size)
val array = list.toArray()
for (i in 0 until 1000) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun addSingleArray() {
val list = create()
list.add(floatArrayOf(189.0f))
assertEquals(1, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f), array)
}
@Test
fun addMultipleArrays() {
val list = create()
list.add(floatArrayOf(189.0f))
list.add(floatArrayOf(289.0f))
list.add(floatArrayOf(389.0f))
assertEquals(3, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f), array)
}
@Test
fun addMultipleBigArrays() {
val list = create()
list.add(floatArrayOf(189.0f))
list.add(floatArrayOf(289.0f, 389.0f))
list.add(floatArrayOf(489.0f, 589.0f, 689.0f))
assertEquals(6, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f, 489.0f, 589.0f, 689.0f), array)
}
@Test
fun addVastArrays() {
val list = create()
for (i in 0 until 1000) {
list.add(floatArrayOf(i.toFloat() * 2.0f))
}
assertEquals(1000, list.size)
val array = list.toArray()
for (i in 0 until 1000) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun addSingleBuffer() {
val list = create()
list.add(wrap(189.0f))
assertEquals(1, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f), array)
}
@Test
fun addMultipleBuffers() {
val list = create()
list.add(wrap(189.0f))
list.add(wrap(289.0f))
list.add(wrap(389.0f))
assertEquals(3, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f), array)
}
@Test
fun addMultipleBigBuffers() {
val list = create()
list.add(wrap(189.0f))
list.add(wrap(289.0f, 389.0f))
list.add(wrap(489.0f, 589.0f, 689.0f))
assertEquals(6, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f, 489.0f, 589.0f, 689.0f), array)
}
@Test
fun addVastBuffers() {
val list = create()
for (i in 0 until 1000) {
list.add(wrap(i.toFloat() * 2.0f))
}
assertEquals(1000, list.size)
val array = list.toArray()
for (i in 0 until 1000) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun addSingleHeapList() {
val list = create()
list.add(HeapArrayFloatList(1).apply { add(189.0f) })
assertEquals(1, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f), array)
}
@Test
fun addMultipleHeapLists() {
val list = create()
list.add(HeapArrayFloatList(1).apply { add(189.0f) })
list.add(HeapArrayFloatList(1).apply { add(289.0f) })
list.add(HeapArrayFloatList(1).apply { add(389.0f) })
assertEquals(3, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f), array)
}
@Test
fun addMultipleBigHeapLists() {
val list = create()
list.add(HeapArrayFloatList(1).apply { add(189.0f) })
list.add(HeapArrayFloatList(1).apply { add(289.0f); add(389.0f) })
list.add(HeapArrayFloatList(1).apply { add(489.0f); add(589.0f); add(689.0f) })
assertEquals(6, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f, 489.0f, 589.0f, 689.0f), array)
}
@Test
fun addVastHeapLists() {
val list = create()
for (i in 0 until 1000) {
list.add(HeapArrayFloatList(1).apply { add(i.toFloat() * 2.0f) })
}
assertEquals(1000, list.size)
val array = list.toArray()
for (i in 0 until 1000) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun addSingleBufferedList() {
val list = create()
list.add(BufferedArrayFloatList(1).apply { add(189.0f) })
assertEquals(1, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f), array)
}
@Test
fun addMultipleBufferedLists() {
val list = create()
list.add(BufferedArrayFloatList(1).apply { add(189.0f) })
list.add(BufferedArrayFloatList(1).apply { add(289.0f) })
list.add(BufferedArrayFloatList(1).apply { add(389.0f) })
assertEquals(3, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f), array)
}
@Test
fun addMultipleBigBufferedLists() {
val list = create()
list.add(BufferedArrayFloatList(1).apply { add(189.0f) })
list.add(BufferedArrayFloatList(1).apply { add(289.0f); add(389.0f) })
list.add(BufferedArrayFloatList(1).apply { add(489.0f); add(589.0f); add(689.0f) })
assertEquals(6, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f, 489.0f, 589.0f, 689.0f), array)
}
@Test
fun addVastBufferedLists() {
val list = create()
for (i in 0 until 1000) {
list.add(BufferedArrayFloatList(1).apply { add(i.toFloat() * 2.0f) })
}
assertEquals(1000, list.size)
val array = list.toArray()
for (i in 0 until 1000) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun addSingleFragmentedList() {
val list = create()
list.add(FragmentedArrayFloatList(1).apply { add(189.0f) })
assertEquals(1, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f), array)
}
@Test
fun addMultipleFragmentedLists() {
val list = create()
list.add(FragmentedArrayFloatList(1).apply { add(189.0f) })
list.add(FragmentedArrayFloatList(1).apply { add(289.0f) })
list.add(FragmentedArrayFloatList(1).apply { add(389.0f) })
assertEquals(3, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f), array)
}
@Test
fun addMultipleBigFragmentedLists() {
val list = create()
list.add(FragmentedArrayFloatList(1).apply { add(189.0f) })
list.add(FragmentedArrayFloatList(1).apply { add(289.0f); add(389.0f) })
list.add(FragmentedArrayFloatList(1).apply { add(489.0f); add(589.0f); add(689.0f) })
assertEquals(6, list.size)
val array = list.toArray()
assertContentEquals(floatArrayOf(189.0f, 289.0f, 389.0f, 489.0f, 589.0f, 689.0f), array)
}
@Test
fun addVastFragmentedLists() {
val list = create()
for (i in 0 until 1000) {
list.add(FragmentedArrayFloatList(1).apply { add(i.toFloat() * 2.0f) })
}
assertEquals(1000, list.size)
val array = list.toArray()
for (i in 0 until 1000) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun fragmentedArray() {
val list = create(120)
list.add(FloatArray(110) { it.toFloat() * 2 })
list.add(FloatArray(50) { 220 + it.toFloat() * 2 })
list.add(320.0f)
val array = list.toArray()
for (i in 0 until 161) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun fragmentedBuffer() {
val list = create(120)
list.add(wrap(*FloatArray(110) { it.toFloat() * 2 }))
list.add(wrap(*FloatArray(50) { 220 + it.toFloat() * 2 }))
list.add(320.0f)
val array = list.toArray()
for (i in 0 until 161) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun fragmentedHeapList() {
val list = create(120)
list.add(HeapArrayFloatList().apply { add(FloatArray(110) { it.toFloat() * 2 }) })
list.add(HeapArrayFloatList().apply { add(FloatArray(50) { 220 + it.toFloat() * 2 }) })
list.add(320.0f)
val array = list.toArray()
for (i in 0 until 161) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun fragmentedBufferedList() {
val list = create(120)
list.add(BufferedArrayFloatList().apply { add(FloatArray(110) { it.toFloat() * 2 }) })
list.add(BufferedArrayFloatList().apply { add(FloatArray(50) { 220 + it.toFloat() * 2 }) })
list.add(320.0f)
val array = list.toArray()
for (i in 0 until 161) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun fragmentedFragmentedList() {
val list = create(120)
list.add(FragmentedArrayFloatList().apply { add(FloatArray(110) { it.toFloat() * 2 }) })
list.add(FragmentedArrayFloatList().apply { add(FloatArray(50) { 220 + it.toFloat() * 2 }) })
list.add(320.0f)
val array = list.toArray()
for (i in 0 until 161) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun fragmentedFragmentedList2() {
val list = create(120)
list.add(FragmentedArrayFloatList(10).apply { add(FloatArray(110) { it.toFloat() * 2 }) })
list.add(FragmentedArrayFloatList(14).apply { add(FloatArray(50) { 220 + it.toFloat() * 2 }) })
list.add(320.0f)
val array = list.toArray()
for (i in 0 until 161) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun ensureSizeArray() {
val list = create(120)
list.add(0.0f)
list.ensureSize(1000)
list.ensureSize(2000)
list.add(FloatArray(1000) { 2.0f + it.toFloat() * 2 })
val array = list.toArray()
for (i in 0 until 1001) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun ensureSizeBuffer() {
val list = create(120)
list.add(0.0f)
list.ensureSize(1000)
list.ensureSize(2000)
list.add(wrap(*FloatArray(1000) { 2.0f + it.toFloat() * 2 }))
val array = list.toArray()
for (i in 0 until 1001) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun ensureSizeHeapList() {
val list = create(120)
list.add(0.0f)
list.ensureSize(1000)
list.ensureSize(2000)
list.add(HeapArrayFloatList().apply { add(FloatArray(1000) { 2.0f + it.toFloat() * 2 }) })
val array = list.toArray()
for (i in 0 until 1001) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun ensureSizeBufferedList() {
val list = create(120)
list.add(0.0f)
list.ensureSize(1000)
list.ensureSize(2000)
list.add(BufferedArrayFloatList().apply { add(FloatArray(1000) { 2.0f + it.toFloat() * 2 }) })
val array = list.toArray()
for (i in 0 until 1001) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
@Test
fun ensureSizeFragmentedList() {
val list = create(120)
list.add(0.0f)
list.ensureSize(1000)
list.ensureSize(2000)
list.add(FragmentedArrayFloatList().apply { add(FloatArray(1000) { 2.0f + it.toFloat() * 2 }) })
val array = list.toArray()
for (i in 0 until 1001) {
assertEquals(array[i], i.toFloat() * 2.0f)
}
}
private fun wrap(vararg array: Float): FloatBuffer {
val buffer = FloatBuffer.wrap(array)
buffer.position(array.size)
return buffer
}
}

View File

@ -0,0 +1,21 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.util.collections.floats
class BufferedFloatListTest : DirectFloatListTest() {
override fun create(initialSize: Int): AbstractFloatList {
return BufferedArrayFloatList(initialSize)
}
}

View File

@ -0,0 +1,45 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.util.collections.floats
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
abstract class DirectFloatListTest : AbstractFloatListTest() {
@Test
fun singleToBuffer() {
val list = create()
if (list !is DirectArrayFloatList) {
return
}
list.add(189.0f)
val buffer = list.toBuffer()
Assertions.assertEquals(buffer.get(0), 189.0f)
Assertions.assertEquals(buffer.position(), 1)
}
@Test
fun multipleToBuffer() {
val list = create()
if (list !is DirectArrayFloatList) {
return
}
list.add(189.0f)
list.add(289.0f)
val buffer = list.toBuffer()
Assertions.assertEquals(buffer.get(0), 189.0f)
Assertions.assertEquals(buffer.get(1), 289.0f)
Assertions.assertEquals(buffer.position(), 2)
}
}

View File

@ -0,0 +1,47 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.util.collections.floats
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class FragmentedFloatListTest : DirectFloatListTest() {
override fun create(initialSize: Int): AbstractFloatList {
return FragmentedArrayFloatList(initialSize)
}
private fun AbstractFloatList.putMixed() {
ensureSize(7)
add(1.0f)
add(2.0f)
add(floatArrayOf(3.0f, 4.0f))
add(5.0f)
add(6.0f)
add(floatArrayOf(7.0f))
}
@Test
fun testMixed() {
val list = FragmentedArrayFloatList(1000)
for (i in 0 until 2000) {
println(i)
list.putMixed()
}
assertEquals(14000, list.size)
assertEquals(14000, list.toArray().size)
assertEquals(14, list.fragments.size)
}
}

View File

@ -0,0 +1,21 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.util.collections.floats
class HeapFloatListTest : AbstractFloatListTest() {
override fun create(initialSize: Int): AbstractFloatList {
return HeapArrayFloatList(initialSize)
}
}