diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/buffer/vertex/FloatOpenGLVertexBuffer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/buffer/vertex/FloatOpenGLVertexBuffer.kt index bb97d7197..6739d5cef 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/buffer/vertex/FloatOpenGLVertexBuffer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/buffer/vertex/FloatOpenGLVertexBuffer.kt @@ -5,7 +5,6 @@ import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.FloatVertexBu import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.PrimitiveTypes import de.bixilon.minosoft.gui.rendering.system.opengl.buffer.FloatOpenGLBuffer import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct -import de.bixilon.minosoft.util.KUtil.clean import org.lwjgl.opengl.ARBVertexArrayObject.glBindVertexArray import org.lwjgl.opengl.ARBVertexArrayObject.glGenVertexArrays import org.lwjgl.opengl.GL11.* @@ -33,7 +32,6 @@ class FloatOpenGLVertexBuffer(override val structure: MeshStruct, data: FloatBuf glBufferData(type.gl, buffer, drawTypes.gl) state = RenderBufferStates.UPLOADED - buffer.clean() _data = null diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/Mesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/Mesh.kt index 2a329046a..10e42befe 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/Mesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/Mesh.kt @@ -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.system.base.buffer.vertex.FloatVertexBuffer import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.PrimitiveTypes -import de.bixilon.minosoft.util.collections.ArrayFloatList +import de.bixilon.minosoft.util.collections.DirectArrayFloatList import glm_.vec2.Vec2 import glm_.vec3.Vec3 @@ -27,8 +27,8 @@ abstract class Mesh( initialCacheSize: Int = 10000, ) { val order = renderWindow.renderSystem.primitiveMeshOrder - private var _data: ArrayFloatList? = ArrayFloatList(initialCacheSize) - var data: ArrayFloatList + private var _data: DirectArrayFloatList? = DirectArrayFloatList(initialCacheSize) + var data: DirectArrayFloatList get() = _data!! set(value) { _data = value @@ -45,8 +45,9 @@ abstract class Mesh( fun load() { buffer = renderWindow.renderSystem.createVertexBuffer(struct, data.buffer, primitiveType) - _data = null buffer.init() + data.unload() + _data = null vertices = buffer.vertices } diff --git a/src/main/java/de/bixilon/minosoft/util/KUtil.kt b/src/main/java/de/bixilon/minosoft/util/KUtil.kt index f0f781afa..53b046608 100644 --- a/src/main/java/de/bixilon/minosoft/util/KUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/KUtil.kt @@ -33,7 +33,6 @@ import glm_.vec2.Vec2t import glm_.vec3.Vec3t import glm_.vec4.Vec4t import okio.Buffer -import org.lwjgl.system.MemoryUtil.memFree import sun.misc.Unsafe import java.io.PrintWriter import java.io.StringWriter @@ -506,8 +505,4 @@ object KUtil { this.get(array) return array } - - fun java.nio.Buffer.clean() { - memFree(this) - } } diff --git a/src/main/java/de/bixilon/minosoft/util/collections/ArrayFloatList.kt b/src/main/java/de/bixilon/minosoft/util/collections/ArrayFloatList.kt index 73a6fabfa..5d763e886 100644 --- a/src/main/java/de/bixilon/minosoft/util/collections/ArrayFloatList.kt +++ b/src/main/java/de/bixilon/minosoft/util/collections/ArrayFloatList.kt @@ -1,34 +1,27 @@ /* - * 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 . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - +* 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 . +* +* This software is not affiliated with Mojang AB, the original developer of Minecraft. +*/ package de.bixilon.minosoft.util.collections -import de.bixilon.minosoft.util.KUtil -import de.bixilon.minosoft.util.KUtil.clean -import org.lwjgl.system.MemoryUtil.memAllocFloat -import java.nio.FloatBuffer - class ArrayFloatList( initialSize: Int = DEFAULT_INITIAL_SIZE, ) { - var buffer: FloatBuffer = memAllocFloat(initialSize) // ToDo: Clear when disconnected - private set + private var data: FloatArray = FloatArray(initialSize) var finalized: Boolean = false private set - val capacity: Int - get() = buffer.capacity() - val size: Int - get() = buffer.position() + val limit: Int + get() = data.size + var size = 0 + private set val isEmpty: Boolean get() = size == 0 @@ -49,66 +42,55 @@ class ArrayFloatList( fun clear() { checkFinalized() - buffer.clean() + size = 0 outputUpToDate = false output = FloatArray(0) } private fun ensureSize(needed: Int) { checkFinalized() - if (capacity - size >= needed) { + if (limit - size >= needed) { return } - var newSize = capacity + var newSize = data.size while (newSize - size < needed) { newSize += nextGrowStep } - val oldBuffer = buffer - buffer = memAllocFloat(newSize) - 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()) - } - oldBuffer.clean() + val oldData = data + data = FloatArray(newSize) + System.arraycopy(oldData, 0, data, 0, oldData.size) } fun add(float: Float) { ensureSize(1) - buffer.put(float) + data[size++] = float outputUpToDate = false } fun addAll(floats: FloatArray) { ensureSize(floats.size) - buffer.put(floats) + System.arraycopy(floats, 0, data, size, floats.size) + size += floats.size outputUpToDate = false } fun addAll(floatList: ArrayFloatList) { ensureSize(floatList.size) - if (FLOAT_PUT_METHOD == null) { // Java < 16 - for (i in 0 until floatList.buffer.position()) { - buffer.put(floatList.buffer.get(i)) - } + val source = if (floatList.finalized) { + floatList.output } else { - FLOAT_PUT_METHOD.invoke(buffer, buffer.position(), floatList.buffer, 0, floatList.buffer.position()) - buffer.position(buffer.position() + floatList.buffer.position()) + floatList.data } + System.arraycopy(source, 0, data, size, floatList.size) + size += floatList.size } private fun checkOutputArray() { if (outputUpToDate) { return } - val position = buffer.position() - output = FloatArray(position) - buffer.position(0) - buffer.get(output, 0, position) - buffer.position(position) + output = FloatArray(size) + System.arraycopy(data, 0, output, 0, size) outputUpToDate = true } @@ -119,22 +101,12 @@ class ArrayFloatList( fun finish() { finalized = true - val oldBuffer = buffer - buffer = memAllocFloat(oldBuffer.position()) - 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()) - } - oldBuffer.clean() + checkOutputArray() + data = FloatArray(0) } private companion object { - private val FLOAT_PUT_METHOD = KUtil.tryCatch { FloatBuffer::class.java.getMethod("put", Int::class.java, FloatBuffer::class.java, Int::class.java, Int::class.java) } private const val DEFAULT_INITIAL_SIZE = 1000 } } diff --git a/src/main/java/de/bixilon/minosoft/util/collections/DirectArrayFloatList.kt b/src/main/java/de/bixilon/minosoft/util/collections/DirectArrayFloatList.kt new file mode 100644 index 000000000..e9772b392 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/collections/DirectArrayFloatList.kt @@ -0,0 +1,153 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.util.collections + +import de.bixilon.minosoft.util.KUtil +import org.lwjgl.system.MemoryUtil.memAllocFloat +import org.lwjgl.system.MemoryUtil.memFree +import java.nio.FloatBuffer + +class DirectArrayFloatList( + initialSize: Int = DEFAULT_INITIAL_SIZE, +) { + var buffer: FloatBuffer = memAllocFloat(initialSize) // ToDo: Clear when disconnected + private set + var finalized: Boolean = false + private set + val capacity: Int + get() = buffer.capacity() + val size: Int + get() = buffer.position() + val isEmpty: Boolean + get() = size == 0 + private var unloaded = false + + private val nextGrowStep = when { + initialSize <= 0 -> DEFAULT_INITIAL_SIZE + initialSize <= 50 -> 50 + else -> initialSize + } + + private var output: FloatArray = FloatArray(0) + private var outputUpToDate = false + + private fun checkFinalized() { + if (finalized) { + throw IllegalStateException("ArrayFloatList is already finalized!") + } + } + + private fun ensureSize(needed: Int) { + checkFinalized() + if (capacity - size >= needed) { + return + } + var newSize = capacity + while (newSize - size < needed) { + newSize += nextGrowStep + } + val oldBuffer = buffer + buffer = memAllocFloat(newSize) + 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) + } + + fun add(float: Float) { + ensureSize(1) + buffer.put(float) + outputUpToDate = false + } + + fun addAll(floats: FloatArray) { + ensureSize(floats.size) + buffer.put(floats) + outputUpToDate = false + } + + fun addAll(floatList: 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()) + } + } + + fun addAll(floatList: ArrayFloatList) { + ensureSize(floatList.size) + buffer.put(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 + } + + fun toArray(): FloatArray { + checkOutputArray() + return output + } + + fun unload() { + check(!unloaded) { "Already unloaded!" } + unloaded = true + finalized = true // Is unloaded + memFree(buffer) + } + + fun finish() { + finalized = true + val oldBuffer = buffer + buffer = memAllocFloat(oldBuffer.position()) + 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 = KUtil.tryCatch { FloatBuffer::class.java.getMethod("put", Int::class.java, FloatBuffer::class.java, Int::class.java, Int::class.java) } + private const val DEFAULT_INITIAL_SIZE = 1000 + } +}