maven: remove apache primitives, improve hud rendering performance A LOT

This commit is contained in:
Bixilon 2021-03-20 19:39:15 +01:00
parent 77af672985
commit 8ffce5f563
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
13 changed files with 137 additions and 46 deletions

View File

@ -346,10 +346,5 @@
<artifactId>moshi-kotlin</artifactId> <artifactId>moshi-kotlin</artifactId>
<version>1.11.0</version> <version>1.11.0</version>
</dependency> </dependency>
<dependency>
<groupId>commons-primitives</groupId>
<artifactId>commons-primitives</artifactId>
<version>1.0</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -215,10 +215,11 @@ open class TextComponent : ChatComponent {
// add all chars // add all chars
for (char in charArray) { for (char in charArray) {
if (char == '\n') { if (char == '\n') {
val yOffset = offset.y offset.x = 0
offset *= 0 offset.y = 0
offset += Vec2(0, yOffset + Font.CHAR_HEIGHT + RenderConstants.TEXT_LINE_PADDING) val yOffset = offset.y + Font.CHAR_HEIGHT + RenderConstants.TEXT_LINE_PADDING
retMaxSize += Vec2(0, yOffset + Font.CHAR_HEIGHT + RenderConstants.TEXT_LINE_PADDING) offset.y += yOffset
retMaxSize.y += yOffset
continue continue
} }
val fontChar = font.getChar(char) val fontChar = font.getChar(char)
@ -228,7 +229,7 @@ open class TextComponent : ChatComponent {
textElement.addChild(ImageElement(charStart, fontChar, charStart + Vec2(scaledWidth, Font.CHAR_HEIGHT), z, color)) textElement.addChild(ImageElement(charStart, fontChar, charStart + Vec2(scaledWidth, Font.CHAR_HEIGHT), z, color))
// ad spacer between chars // ad spacer between chars
offset += Vec2i(scaledWidth + Font.SPACE_BETWEEN_CHARS, 0f) offset.x += scaledWidth + Font.SPACE_BETWEEN_CHARS
if (offset.x > retMaxSize.x) { if (offset.x > retMaxSize.x) {
retMaxSize.x += scaledWidth + Font.SPACE_BETWEEN_CHARS retMaxSize.x += scaledWidth + Font.SPACE_BETWEEN_CHARS
} }

View File

@ -46,6 +46,7 @@ object RenderConstants {
const val CHUNK_SECTIONS_PER_MESH = 1 const val CHUNK_SECTIONS_PER_MESH = 1
const val FRUSTUM_CULLING_ENABLED = true const val FRUSTUM_CULLING_ENABLED = true
const val SHOW_FPS_IN_WINDOW_TITLE = true
const val MAXIMUM_CALLS_PER_FRAME = 10 const val MAXIMUM_CALLS_PER_FRAME = 10
} }

View File

@ -383,7 +383,9 @@ class RenderWindow(
} }
renderStats.endFrame() renderStats.endFrame()
glfwSetWindowTitle(windowId, "FPS: ${renderStats.fpsLastSecond}") if (RenderConstants.SHOW_FPS_IN_WINDOW_TITLE) {
glfwSetWindowTitle(windowId, "Minosoft | FPS: ${renderStats.fpsLastSecond}")
}
} }
} }

View File

@ -24,20 +24,12 @@ import org.lwjgl.opengl.GL11.GL_FLOAT
import org.lwjgl.opengl.GL20.glEnableVertexAttribArray import org.lwjgl.opengl.GL20.glEnableVertexAttribArray
import org.lwjgl.opengl.GL20.glVertexAttribPointer import org.lwjgl.opengl.GL20.glVertexAttribPointer
class SectionArrayMesh : Mesh() { class SectionArrayMesh : Mesh(initialCacheSize = 100000) {
var lowestBlockHeight = 0 var lowestBlockHeight = 0
var highestBlockHeight = 0 var highestBlockHeight = 0
fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture, tintColor: RGBColor?, lightLevel: Int = 14) { fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture, tintColor: RGBColor?, lightLevel: Int = 14) {
val data = data!! val data = data!!
data.add(position.x)
data.add(position.y)
data.add(position.z)
data.add(textureCoordinates.x * texture.uvEnd.x)
data.add(textureCoordinates.y * texture.uvEnd.y)
data.add(Float.fromBits((texture.arrayId shl 24) or texture.arrayLayer))
data.add(Float.fromBits(texture.properties.animation?.animationId ?: -1))
val color = tintColor ?: ChatColors.WHITE val color = tintColor ?: ChatColors.WHITE
@ -45,8 +37,17 @@ class SectionArrayMesh : Mesh() {
val lightColor = RGBColor(color.red / lightFactor, color.green / lightFactor, color.blue / lightFactor) val lightColor = RGBColor(color.red / lightFactor, color.green / lightFactor, color.blue / lightFactor)
data.addAll(floatArrayOf(
data.add(Float.fromBits(lightColor.color ushr 8)) position.x,
position.y,
position.z,
textureCoordinates.x * texture.uvEnd.x,
textureCoordinates.y * texture.uvEnd.y,
Float.fromBits((texture.arrayId shl 24) or texture.arrayLayer),
Float.fromBits(texture.properties.animation?.animationId ?: -1),
Float.fromBits(lightColor.color ushr 8),
)
)
} }
override fun load() { override fun load() {

View File

@ -15,33 +15,37 @@ package de.bixilon.minosoft.gui.rendering.hud
import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.textures.Texture import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.util.collections.ArrayFloatList
import glm_.vec2.Vec2 import glm_.vec2.Vec2
import glm_.vec3.Vec3 import glm_.vec3.Vec3
import org.apache.commons.collections.primitives.ArrayFloatList
class HUDCacheMesh { class HUDCacheMesh(
private val data = ArrayFloatList() initialCacheSize: Int = 1000,
) {
private val data = ArrayFloatList(initialCacheSize)
val cache: ArrayFloatList val cache: ArrayFloatList
get() = data get() = data
fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture?, tintColor: RGBColor? = null) { fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture?, tintColor: RGBColor? = null) {
data.add(position.x) data.addAll(floatArrayOf(
data.add(position.y) position.x,
data.add(position.z) position.y,
data.add(textureCoordinates.x) position.z,
data.add(textureCoordinates.y) textureCoordinates.x,
data.add(Float.fromBits((texture?.arrayLayer ?: 0) or ((texture?.arrayId ?: 0) shl 24))) textureCoordinates.y,
Float.fromBits((texture?.arrayLayer ?: 0) or ((texture?.arrayId ?: 0) shl 24)),
if (tintColor == null) { if (tintColor == null) {
data.add(0f) 0f
} else { } else {
data.add(Float.fromBits(tintColor.color)) Float.fromBits(tintColor.color)
} },
))
} }
val size: Int val size: Int
get() = data.size() get() = data.size
fun isEmpty(): Boolean { fun isEmpty(): Boolean {
return data.isEmpty return data.isEmpty

View File

@ -19,6 +19,7 @@ import glm_.vec2.Vec2i
abstract class Element( abstract class Element(
private var _start: Vec2i, private var _start: Vec2i,
initialCacheSize: Int = 1000,
) { ) {
var start: Vec2i var start: Vec2i
get() { get() {
@ -30,7 +31,7 @@ abstract class Element(
clearCache() clearCache()
} }
val cache = HUDCacheMesh() val cache = HUDCacheMesh(initialCacheSize)
open var parent: Element? = null open var parent: Element? = null
var size: Vec2i = Vec2i() var size: Vec2i = Vec2i()

View File

@ -18,7 +18,8 @@ import glm_.vec2.Vec2i
abstract class EndElement( abstract class EndElement(
start: Vec2i, start: Vec2i,
private var _end: Vec2i, private var _end: Vec2i,
) : Element(start) { initialCacheSize: Int = 10000,
) : Element(start, initialCacheSize = initialCacheSize) {
var end: Vec2i var end: Vec2i
get() { get() {
return _end return _end

View File

@ -36,7 +36,7 @@ class HealthBar(
private val singleHeartSize = blackHeartContainerAtlasElement.binding.size private val singleHeartSize = blackHeartContainerAtlasElement.binding.size
private val width = singleHeartSize.x * MAX_HEARTS_IN_ROW private val width = singleHeartSize.x * MAX_HEARTS_IN_ROW
private val alternativeText = TextElement(font = font, start = Vec2i(), background = false) private val alternativeText = TextElement(font = font, start = Vec2i(0, 0), background = false)
private var _value = 0.0f private var _value = 0.0f
var value: Float var value: Float
get() = _value get() = _value

View File

@ -28,7 +28,8 @@ class ImageElement(
end: Vec2i = textureLike?.size ?: Vec2i(0, 0), end: Vec2i = textureLike?.size ?: Vec2i(0, 0),
val z: Int = 0, val z: Int = 0,
val tintColor: RGBColor? = null, val tintColor: RGBColor? = null,
) : EndElement(start, end) { ) : EndElement(start, end, initialCacheSize = 42) {
init { init {
recalculateSize() recalculateSize()
} }

View File

@ -49,7 +49,7 @@ class TextElement(
size = if (text.message.isBlank()) { size = if (text.message.isBlank()) {
Vec2i(0, Font.CHAR_HEIGHT) Vec2i(0, Font.CHAR_HEIGHT)
} else { } else {
val textSize = Vec2i() val textSize = Vec2i(0, 0)
text.prepareRender(Vec2i(0, 1), Vec2i(), font, this, this.z + z + 1, textSize) text.prepareRender(Vec2i(0, 1), Vec2i(), font, this, this.z + z + 1, textSize)
if (background) { if (background) {

View File

@ -13,13 +13,15 @@
package de.bixilon.minosoft.gui.rendering.util package de.bixilon.minosoft.gui.rendering.util
import org.apache.commons.collections.primitives.ArrayFloatList import de.bixilon.minosoft.util.collections.ArrayFloatList
import org.lwjgl.opengl.GL11.GL_TRIANGLES import org.lwjgl.opengl.GL11.GL_TRIANGLES
import org.lwjgl.opengl.GL11.glDrawArrays import org.lwjgl.opengl.GL11.glDrawArrays
import org.lwjgl.opengl.GL30.* import org.lwjgl.opengl.GL30.*
abstract class Mesh { abstract class Mesh(
protected var data: ArrayFloatList? = ArrayFloatList() initialCacheSize: Int = 10000,
) {
protected var data: ArrayFloatList? = ArrayFloatList(initialCacheSize)
private var vao: Int = -1 private var vao: Int = -1
private var vbo: Int = -1 private var vbo: Int = -1
var trianglesCount: Int = -1 var trianglesCount: Int = -1
@ -34,7 +36,7 @@ abstract class Mesh {
protected fun initializeBuffers(floatsPerVertex: Int) { protected fun initializeBuffers(floatsPerVertex: Int) {
check(state == MeshStates.PREPARING) { "Mesh already loaded: $state" } check(state == MeshStates.PREPARING) { "Mesh already loaded: $state" }
trianglesCount = data!!.size() / floatsPerVertex trianglesCount = data!!.size / floatsPerVertex
vao = glGenVertexArrays() vao = glGenVertexArrays()
vbo = glGenBuffers() vbo = glGenBuffers()
glBindVertexArray(vao) glBindVertexArray(vao)

View File

@ -0,0 +1,82 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.util.collections
class ArrayFloatList(
private val initialSize: Int = 1000,
) {
private var data: FloatArray = FloatArray(initialSize)
val limit: Int
get() = data.size
var size = 0
private set
val isEmpty: Boolean
get() = size == 0
private var output: FloatArray = FloatArray(0)
private var outputUpToDate = false
fun clear() {
size = 0
data = FloatArray(initialSize)
outputUpToDate = false
output = FloatArray(0)
}
private fun ensureSize(needed: Int) {
if (limit - size >= needed) {
return
}
var newSize = data.size
while (newSize - size < needed) {
newSize += initialSize
}
val oldData = data
data = FloatArray(newSize)
System.arraycopy(oldData, 0, data, 0, oldData.size)
}
fun add(float: Float) {
ensureSize(1)
data[size++] = float
outputUpToDate = false
}
fun addAll(floats: FloatArray) {
ensureSize(floats.size)
System.arraycopy(floats, 0, data, size, floats.size)
size += floats.size
outputUpToDate = false
}
fun addAll(floats: ArrayFloatList) {
ensureSize(floats.size)
System.arraycopy(floats.data, 0, data, size, floats.size)
size += floats.size
}
private fun checkOutputArray() {
if (outputUpToDate) {
return
}
output = FloatArray(size)
System.arraycopy(data, 0, output, 0, size)
outputUpToDate = true
}
fun toArray(): FloatArray {
checkOutputArray()
return output
}
}