From e2df230da41b1931e55d386e3c66c8589a6a1025 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Mon, 2 May 2022 20:00:19 +0200 Subject: [PATCH] load dynamic textures --- .../properties/textures/PlayerTexture.kt | 5 ++ .../gui/eros/util/JavaFXAccountUtil.kt | 2 +- .../minosoft/gui/rendering/RenderWindow.kt | 3 +- .../elements/primitive/DynamicImageElement.kt | 4 ++ .../gui/hud/elements/tab/TabListElement.kt | 2 +- .../hud/elements/tab/TabListEntryElement.kt | 7 ++- .../system/base/texture/TextureManager.kt | 27 +++++--- .../texture/dynamic/DynamicTextureArray.kt | 11 +++- .../texture/dynamic/OpenGLDynamicTexture.kt | 10 ++- .../dynamic/OpenGLDynamicTextureArray.kt | 62 +++++++++++++++---- .../network/network/client/NettyClient.kt | 2 +- 11 files changed, 104 insertions(+), 31 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTexture.kt b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTexture.kt index a604737df..c5c79a81a 100644 --- a/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTexture.kt +++ b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTexture.kt @@ -18,6 +18,7 @@ import de.bixilon.kutil.url.URLUtil.checkWeb import de.bixilon.minosoft.assets.util.FileAssetsUtil import de.bixilon.minosoft.assets.util.FileUtil import java.net.URL +import java.util.* open class PlayerTexture( val url: URL, @@ -65,5 +66,9 @@ open class PlayerTexture( } return false } + + fun UUID.isSteve(): Boolean { + return hashCode() % 2 == 0 + } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXAccountUtil.kt b/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXAccountUtil.kt index d01c97d8c..0186a5e4e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXAccountUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXAccountUtil.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2021 Moritz Zwerger + * 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. * diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt index 52c7164f8..78949c601 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -150,7 +150,8 @@ class RenderWindow( val initLatch = CountUpAndDownLatch(1, latch) Log.log(LogMessageType.RENDERING_LOADING, LogLevels.VERBOSE) { "Generating font and gathering textures (${stopwatch.labTime()})..." } textureManager.dynamicTextures.load(initLatch) - textureManager.loadDefaultTextures(connection.assetsManager) + textureManager.loadDefaultSkins(connection) + textureManager.loadDefaultTextures() font = FontLoader.load(this, initLatch) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/DynamicImageElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/DynamicImageElement.kt index 512bc44ae..6799dd2df 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/DynamicImageElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/DynamicImageElement.kt @@ -34,8 +34,11 @@ open class DynamicImageElement( size: Vec2i = Vec2i.EMPTY, tint: RGBColor = ChatColors.WHITE, ) : Element(guiRenderer, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6) { + var texture: DynamicTexture? = texture set(value) { + field?.usages?.decrementAndGet() + value?.usages?.incrementAndGet() field = value cacheUpToDate = false } @@ -71,6 +74,7 @@ open class DynamicImageElement( init { this.size = size + texture?.usages?.incrementAndGet() } override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListElement.kt index 926b52d7c..69c36552d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListElement.kt @@ -202,7 +202,7 @@ class TabListElement(guiRenderer: GUIRenderer) : Element(guiRenderer), LayoutedE fun update(uuid: UUID) { val item = guiRenderer.renderWindow.connection.tabList.tabListItemsByUUID[uuid] ?: return - val entry = entries.getOrPut(uuid) { TabListEntryElement(guiRenderer, this, item, 0) } + val entry = entries.getOrPut(uuid) { TabListEntryElement(guiRenderer, this, uuid, item, 0) } lock.lock() entry.silentApply() lock.unlock() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListEntryElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListEntryElement.kt index 6e3821378..4b7b2307e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListEntryElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListEntryElement.kt @@ -33,10 +33,12 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY import de.bixilon.minosoft.util.KUtil.nullCompare import java.lang.Integer.max +import java.util.* class TabListEntryElement( guiRenderer: GUIRenderer, val tabList: TabListElement, + uuid: UUID, val item: TabListItem, width: Int, ) : Element(guiRenderer), Pollable, Comparable { @@ -47,7 +49,7 @@ class TabListEntryElement( private val background: ColorElement - private val skinElement = DynamicImageElement(guiRenderer, guiRenderer.renderWindow.textureManager.alexTexture, uvStart = Vec2(0.125), uvEnd = Vec2(0.25), size = Vec2i(512, 512)) + private val skinElement = DynamicImageElement(guiRenderer, renderWindow.textureManager.getSkin(uuid, item.properties.textures), uvStart = Vec2(0.125), uvEnd = Vec2(0.25), size = Vec2i(8, 8)) // private val skinElement = ImageElement(guiRenderer, guiRenderer.renderWindow.textureManager.steveTexture, uvStart = Vec2(0.125), uvEnd = Vec2(0.25), size = Vec2i(512, 512)) private val nameElement = TextElement(guiRenderer, "", background = false, parent = this) @@ -82,9 +84,8 @@ class TabListEntryElement( } override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) { - skinElement background.render(offset, consumer, options) - skinElement.render(offset, consumer, options) + skinElement.render(offset + Vec2i(PADDING, PADDING), consumer, options) nameElement.render(offset + Vec2i(skinElement.size.x + PADDING, PADDING), consumer, options) pingElement.render(offset + Vec2i(HorizontalAlignments.RIGHT.getOffset(maxSize.x, pingElement.size.x + PADDING), PADDING), consumer, options) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt index 06ac1a3b9..a62ebb428 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt @@ -16,7 +16,8 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kutil.uuid.UUIDUtil.toUUID -import de.bixilon.minosoft.assets.AssetsManager +import de.bixilon.minosoft.data.player.properties.textures.PlayerTexture.Companion.isSteve +import de.bixilon.minosoft.data.player.properties.textures.PlayerTextures import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.gui.atlas.TextureLikeTexture @@ -25,7 +26,9 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicText import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil.readTexture import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture +import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.util.KUtil.toResourceLocation +import java.util.* abstract class TextureManager { abstract val staticTextures: StaticTextureArray @@ -39,21 +42,31 @@ abstract class TextureManager { private set lateinit var alexTexture: DynamicTexture private set + lateinit var skin: DynamicTexture + private set - fun loadDefaultTextures(assetsManager: AssetsManager) { + fun loadDefaultTextures() { if (this::debugTexture.isInitialized) { throw IllegalStateException("Already initialized!") } debugTexture = staticTextures.createTexture(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION) // steveTexture = staticTextures.createTexture("minecraft:entity/steve".toResourceLocation().texture()) whiteTexture = TextureLikeTexture(texture = staticTextures.createTexture(ResourceLocation("minosoft:textures/white.png")), uvStart = Vec2(0.0f, 0.0f), uvEnd = Vec2(0.001f, 0.001f), size = Vec2i(16, 16)) - - loadDefaultSkins(assetsManager) } - private fun loadDefaultSkins(assetsManager: AssetsManager) { + fun loadDefaultSkins(connection: PlayConnection) { // ToDo: For testing purposes only, they will be moved to static textures - steveTexture = dynamicTextures.push("3780a46b-a725-4b22-8366-01056c698386".toUUID()) { assetsManager["minecraft:entity/steve".toResourceLocation().texture()].readTexture().second } - alexTexture = dynamicTextures.push("3780a46b-a725-4b22-8366-01056c698386".toUUID()) { assetsManager["minecraft:entity/alex".toResourceLocation().texture()].readTexture().second } + steveTexture = dynamicTextures.pushBuffer("3780a46b-a725-4b22-8366-01056c698386".toUUID()) { connection.assetsManager["minecraft:entity/steve".toResourceLocation().texture()].readTexture().second } + alexTexture = dynamicTextures.pushBuffer("3780a46b-a725-4b22-8366-01056c698386".toUUID()) { connection.assetsManager["minecraft:entity/alex".toResourceLocation().texture()].readTexture().second } + skin = getSkin(connection.player.uuid ?: UUID.randomUUID(), connection.account.properties?.textures) + } + + + fun getSkin(uuid: UUID, properties: PlayerTextures?): DynamicTexture { + properties?.skin?.let { return dynamicTextures.pushRawArray(uuid) { it.read() } } + if (uuid.isSteve()) { + return steveTexture + } + return alexTexture } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTextureArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTextureArray.kt index 608d10d96..2abba40a0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTextureArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTextureArray.kt @@ -14,13 +14,18 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureArray +import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil.readTexture +import java.io.ByteArrayInputStream import java.nio.ByteBuffer import java.util.* interface DynamicTextureArray : TextureArray { val size: Int - fun push(identifier: UUID, data: () -> ByteBuffer): DynamicTexture - fun remove(texture: DynamicTexture) - fun remove(uuid: UUID) + fun pushBuffer(identifier: UUID, data: () -> ByteBuffer): DynamicTexture + fun pushArray(identifier: UUID, data: () -> ByteArray): DynamicTexture + + fun pushRawArray(identifier: UUID, data: () -> ByteArray): DynamicTexture { + return pushBuffer(identifier) { ByteArrayInputStream(data()).readTexture().second } + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTexture.kt index 54961c6cc..c503ce0a5 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTexture.kt @@ -19,7 +19,15 @@ import java.util.concurrent.atomic.AtomicInteger class OpenGLDynamicTexture( override val uuid: UUID, - override val shaderId: Int, + shaderId: Int, ) : DynamicTexture { override val usages = AtomicInteger() + + override val shaderId: Int = shaderId + get() { + if (usages.get() == 0) { + throw IllegalStateException("Texture was eventually garbage collected") + } + return field + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTextureArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTextureArray.kt index 4491970ab..fe4762276 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTextureArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTextureArray.kt @@ -32,33 +32,42 @@ import java.util.* class OpenGLDynamicTextureArray( val renderWindow: RenderWindow, val index: Int = 7, + initialSize: Int = 32, val resolution: Int, ) : DynamicTextureArray { - private val textures: Array = arrayOfNulls(2) + private val textures: Array = arrayOfNulls(initialSize) private var textureId = -1 - @Deprecated("temp") - private var lastTextureId = 0 - override val size: Int - get() = 2 + get() { + var size = 0 + for (texture in textures) { + if (texture == null) { + continue + } + size++ + } + return size + } - override fun remove(uuid: UUID) { - TODO("Not yet implemented") + override fun pushArray(identifier: UUID, data: () -> ByteArray): DynamicTexture { + return pushBuffer(identifier) { ByteBuffer.wrap(data()) } } - override fun remove(texture: DynamicTexture) { - TODO("Not yet implemented") - } - - override fun push(identifier: UUID, data: () -> ByteBuffer): OpenGLDynamicTexture { + override fun pushBuffer(identifier: UUID, data: () -> ByteBuffer): OpenGLDynamicTexture { check(textureId >= 0) { "Dynamic texture array not yet initialized!" } + cleanup() + for (texture in textures) { + if (texture?.uuid == identifier) { + return texture + } + } val bytes = data() check(bytes.limit() == resolution * resolution * 4) { "Texture must have a size of ${resolution}x${resolution}" } val mipmaps = OpenGLTextureUtil.generateMipMaps(bytes, Vec2i(resolution, resolution)) - val index = lastTextureId++ + val index = getNextIndex() glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) @@ -94,4 +103,31 @@ class OpenGLDynamicTextureArray( glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) shader.setTexture("$name[$index]", index) } + + private fun getNextIndex(): Int { + for ((index, texture) in textures.withIndex()) { + if (texture == null) { + return index + } + } + val nextIndex = textures.size + grow() + return nextIndex + } + + private fun grow() { + TODO() + } + + private fun cleanup() { + for ((index, texture) in textures.withIndex()) { + if (texture == null) { + continue + } + if (texture.usages.get() > 0) { + continue + } + textures[index] = null + } + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NettyClient.kt b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NettyClient.kt index d19f26998..72b4157ad 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NettyClient.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NettyClient.kt @@ -186,7 +186,7 @@ class NettyClient( if (RunConfiguration.DISABLE_EROS || connection !is StatusConnection) { Log.log(LogMessageType.NETWORK_PACKETS_IN, LogLevels.WARN) { cause } } - if (cause !is NetworkException || cause is CriticalNetworkException) { + if (cause !is NetworkException || cause is CriticalNetworkException || state == ProtocolStates.LOGIN) { connection.error = cause if (reportErrors && !ErosCrashReport.alreadyCrashed) { cause.report()