From e7f3891cc436c869d8514d53f199e01504ee1c52 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Mon, 2 May 2022 22:24:04 +0200 Subject: [PATCH] load dynamic textures async, fix some tab list bugs --- .../bixilon/minosoft/data/accounts/Account.kt | 2 + .../types/microsoft/MicrosoftAccount.kt | 2 +- .../accounts/types/mojang/MojangAccount.kt | 2 +- .../accounts/types/offline/OfflineAccount.kt | 2 + .../player/properties/PlayerProperties.kt | 2 +- .../properties/textures/PlayerTexture.kt | 6 +++ .../properties/textures/PlayerTextures.kt | 2 +- .../minosoft/gui/rendering/RenderWindow.kt | 3 ++ .../elements/primitive/DynamicImageElement.kt | 20 +++++++-- .../hud/elements/tab/TabListEntryElement.kt | 6 +-- .../system/base/texture/TextureArray.kt | 1 + .../system/base/texture/TextureManager.kt | 25 +++++++---- .../base/texture/dynamic/DynamicTexture.kt | 4 ++ .../texture/dynamic/DynamicTextureState.kt | 22 ++++++++++ .../opengl/texture/OpenGLTextureArray.kt | 18 ++++++-- .../texture/dynamic/OpenGLDynamicTexture.kt | 15 ++++++- .../dynamic/OpenGLDynamicTextureArray.kt | 42 +++++++++++++------ .../gui/rendering/world/WorldRenderer.kt | 1 + .../packets/s2c/play/tab/TabListS2CP.kt | 6 ++- 19 files changed, 145 insertions(+), 36 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTextureState.kt diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/Account.kt b/src/main/java/de/bixilon/minosoft/data/accounts/Account.kt index 18ae96829..6611fd6e6 100644 --- a/src/main/java/de/bixilon/minosoft/data/accounts/Account.kt +++ b/src/main/java/de/bixilon/minosoft/data/accounts/Account.kt @@ -27,6 +27,7 @@ import de.bixilon.minosoft.data.accounts.types.offline.OfflineAccount import de.bixilon.minosoft.data.player.properties.PlayerProperties import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection +import java.util.* @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes( @@ -42,6 +43,7 @@ abstract class Account( abstract val properties: PlayerProperties? @get:JsonIgnore @set:JsonIgnore open var state: AccountStates by watched(AccountStates.UNCHECKED) @get:JsonIgnore open var error: Throwable? by watched(null) + abstract val uuid: UUID @Transient @JsonIgnore diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/types/microsoft/MicrosoftAccount.kt b/src/main/java/de/bixilon/minosoft/data/accounts/types/microsoft/MicrosoftAccount.kt index 6048346fd..80487b79a 100644 --- a/src/main/java/de/bixilon/minosoft/data/accounts/types/microsoft/MicrosoftAccount.kt +++ b/src/main/java/de/bixilon/minosoft/data/accounts/types/microsoft/MicrosoftAccount.kt @@ -32,7 +32,7 @@ import java.net.ConnectException import java.util.* class MicrosoftAccount( - val uuid: UUID, + override val uuid: UUID, username: String, @field:JsonProperty private var msa: MicrosoftTokens, @field:JsonProperty private var minecraft: MinecraftTokens, diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/types/mojang/MojangAccount.kt b/src/main/java/de/bixilon/minosoft/data/accounts/types/mojang/MojangAccount.kt index a3284ee26..a0a228908 100644 --- a/src/main/java/de/bixilon/minosoft/data/accounts/types/mojang/MojangAccount.kt +++ b/src/main/java/de/bixilon/minosoft/data/accounts/types/mojang/MojangAccount.kt @@ -38,7 +38,7 @@ import java.util.* class MojangAccount( override val id: String, username: String, - val uuid: UUID, + override val uuid: UUID, val email: String, @field:JsonProperty private var accessToken: String, override val properties: PlayerProperties?, diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/types/offline/OfflineAccount.kt b/src/main/java/de/bixilon/minosoft/data/accounts/types/offline/OfflineAccount.kt index 2708cc138..441832299 100644 --- a/src/main/java/de/bixilon/minosoft/data/accounts/types/offline/OfflineAccount.kt +++ b/src/main/java/de/bixilon/minosoft/data/accounts/types/offline/OfflineAccount.kt @@ -21,9 +21,11 @@ import de.bixilon.minosoft.data.player.properties.PlayerProperties import de.bixilon.minosoft.data.registries.CompanionResourceLocation import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.util.KUtil.toResourceLocation +import java.util.* class OfflineAccount(username: String) : Account(username) { override val id: String = username + override val uuid: UUID = UUID("OfflinePlayer:$username".hashCode().toLong(), 0L) // ToDo override val type: ResourceLocation = RESOURCE_LOCATION override var state: AccountStates get() = AccountStates.WORKING diff --git a/src/main/java/de/bixilon/minosoft/data/player/properties/PlayerProperties.kt b/src/main/java/de/bixilon/minosoft/data/player/properties/PlayerProperties.kt index d0ec672c1..d93ac0b13 100644 --- a/src/main/java/de/bixilon/minosoft/data/player/properties/PlayerProperties.kt +++ b/src/main/java/de/bixilon/minosoft/data/player/properties/PlayerProperties.kt @@ -22,7 +22,7 @@ import de.bixilon.minosoft.data.player.properties.textures.PlayerTextures import java.net.URL import java.util.* -class PlayerProperties( +data class PlayerProperties( @JsonInclude(JsonInclude.Include.NON_EMPTY) val textures: PlayerTextures? = null, ) { 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 c5c79a81a..3b2c72dec 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 @@ -17,6 +17,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore import de.bixilon.kutil.url.URLUtil.checkWeb import de.bixilon.minosoft.assets.util.FileAssetsUtil import de.bixilon.minosoft.assets.util.FileUtil +import de.bixilon.minosoft.util.logging.Log +import de.bixilon.minosoft.util.logging.LogLevels +import de.bixilon.minosoft.util.logging.LogMessageType import java.net.URL import java.util.* @@ -33,7 +36,9 @@ open class PlayerTexture( check(urlMatches(url, ALLOWED_DOMAINS) && !urlMatches(url, BLOCKED_DOMAINS)) { "URL hostname is not allowed!" } } + @Synchronized fun read(): ByteArray { + this.data?.let { return it } val sha256 = when (url.host) { "textures.minecraft.net" -> url.file.split("/").last() else -> TODO("Can not get texture identifier!") @@ -50,6 +55,7 @@ open class PlayerTexture( throw IllegalStateException("Texture is too big!") } val data = FileAssetsUtil.saveAndGet(input) + Log.log(LogMessageType.ASSETS, LogLevels.VERBOSE) { "Downloaded skin ($url)" } return data.second } diff --git a/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTextures.kt b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTextures.kt index dab6a17dc..d2c02e43d 100644 --- a/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTextures.kt +++ b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTextures.kt @@ -22,7 +22,7 @@ import de.bixilon.minosoft.util.YggdrasilUtil import de.bixilon.minosoft.util.json.Jackson import java.util.* -class PlayerTextures( +data class PlayerTextures( @JsonInclude(JsonInclude.Include.NON_EMPTY) val name: String?, @JsonInclude(JsonInclude.Include.NON_EMPTY) val uuid: UUID?, @JsonInclude(JsonInclude.Include.NON_EMPTY) val date: Date?, 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 78949c601..d983aca20 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -211,6 +211,9 @@ class RenderWindow( connection.fireEvent(ResizeWindowEvent(previousSize = Vec2i(0, 0), size = window.size)) + textureManager.dynamicTextures.activate() + textureManager.staticTextures.activate() + Log.log(LogMessageType.RENDERING_LOADING) { "Rendering is fully prepared in ${stopwatch.totalTime()}" } initialized = true latch.dec() 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 6799dd2df..943898c63 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 @@ -22,7 +22,9 @@ import de.bixilon.minosoft.gui.rendering.gui.elements.Element import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions +import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture +import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY @@ -33,12 +35,15 @@ open class DynamicImageElement( uvEnd: Vec2 = Vec2(1.0f, 1.0f), size: Vec2i = Vec2i.EMPTY, tint: RGBColor = ChatColors.WHITE, + parent: Element? = null, ) : Element(guiRenderer, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6) { - var texture: DynamicTexture? = texture + var texture: DynamicTexture? = null set(value) { field?.usages?.decrementAndGet() + field?.onStateChange = null value?.usages?.incrementAndGet() + value?.onStateChange = { forceApply() } field = value cacheUpToDate = false } @@ -74,11 +79,20 @@ open class DynamicImageElement( init { this.size = size - texture?.usages?.incrementAndGet() + this.texture = texture + this.parent = parent + } + + private fun getAvailableTexture(): ShaderIdentifiable { + val texture = texture ?: return renderWindow.textureManager.whiteTexture.texture + if (texture.state != DynamicTextureState.LOADED) { + return renderWindow.textureManager.whiteTexture.texture + } + return texture } override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) { - consumer.addQuad(offset, offset + size, texture ?: return, uvStart, uvEnd, tint, options) + consumer.addQuad(offset, offset + size, getAvailableTexture(), uvStart, uvEnd, tint, options) } override fun forceSilentApply() = Unit 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 4b7b2307e..5e3cd0bd6 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 @@ -49,7 +49,7 @@ class TabListEntryElement( private val background: ColorElement - 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 = DynamicImageElement(guiRenderer, renderWindow.textureManager.getSkin(uuid, item.properties), uvStart = Vec2(0.125), uvEnd = Vec2(0.25), size = Vec2i(8, 8), parent = this) // 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) @@ -86,7 +86,7 @@ class TabListEntryElement( override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) { background.render(offset, consumer, options) skinElement.render(offset + Vec2i(PADDING, PADDING), consumer, options) - nameElement.render(offset + Vec2i(skinElement.size.x + PADDING, PADDING), consumer, options) + nameElement.render(offset + Vec2i(skinElement.size.x + PADDING * 3, PADDING), consumer, options) pingElement.render(offset + Vec2i(HorizontalAlignments.RIGHT.getOffset(maxSize.x, pingElement.size.x + PADDING), PADDING), consumer, options) } @@ -104,7 +104,7 @@ class TabListEntryElement( nameElement.text = displayName - this.prefSize = Vec2i((PADDING * 3) + skinElement.prefSize.x + nameElement.prefSize.x + INNER_MARGIN + pingElement.prefSize.x, HEIGHT) + this.prefSize = Vec2i((PADDING * 6) + skinElement.prefSize.x + nameElement.prefSize.x + INNER_MARGIN + pingElement.prefSize.x, HEIGHT) background.size = size cacheUpToDate = false } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureArray.kt index 44fd3f561..1ee547d83 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureArray.kt @@ -19,5 +19,6 @@ import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader interface TextureArray { fun load(latch: CountUpAndDownLatch) + fun activate() fun use(shader: Shader, name: String = "uTextures") } 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 a62ebb428..ab3ce4155 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 @@ -15,9 +15,9 @@ 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.config.profile.profiles.account.AccountProfileManager +import de.bixilon.minosoft.data.player.properties.PlayerProperties 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 @@ -56,14 +56,25 @@ abstract class TextureManager { fun loadDefaultSkins(connection: PlayConnection) { // ToDo: For testing purposes only, they will be moved to static textures - 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) + steveTexture = dynamicTextures.pushBuffer(UUID(0L, 0L)) { connection.assetsManager["minecraft:entity/steve".toResourceLocation().texture()].readTexture().second }.apply { usages.incrementAndGet() } + alexTexture = dynamicTextures.pushBuffer(UUID(1L, 0L)) { connection.assetsManager["minecraft:entity/alex".toResourceLocation().texture()].readTexture().second }.apply { usages.incrementAndGet() } + skin = getSkin(connection.account.uuid, connection.account.properties).apply { usages.incrementAndGet() } } - fun getSkin(uuid: UUID, properties: PlayerTextures?): DynamicTexture { - properties?.skin?.let { return dynamicTextures.pushRawArray(uuid) { it.read() } } + fun getSkin(uuid: UUID, properties: PlayerProperties?): DynamicTexture { + var properties = properties + if (properties == null) { + for (account in AccountProfileManager.selected.entries.values) { + if (account.uuid == uuid) { + properties = account.properties + } + } + if (properties == null) { + properties = PlayerProperties.fetch(uuid) // ToDo: async + } + } + properties.textures?.skin?.let { return dynamicTextures.pushRawArray(uuid) { it.read() } } if (uuid.isSteve()) { return steveTexture } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTexture.kt index 44b673b12..8e6d426f1 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTexture.kt @@ -20,4 +20,8 @@ import java.util.concurrent.atomic.AtomicInteger interface DynamicTexture : ShaderIdentifiable { val uuid: UUID val usages: AtomicInteger + + val state: DynamicTextureState + + var onStateChange: (() -> Unit)? } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTextureState.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTextureState.kt new file mode 100644 index 000000000..b49962f37 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTextureState.kt @@ -0,0 +1,22 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic + +enum class DynamicTextureState { + WAITING, + LOADING, + LOADED, + UNLOADED, + ; +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureArray.kt index 2e3d043c4..87c3110e3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureArray.kt @@ -191,16 +191,26 @@ class OpenGLTextureArray( state = TextureArrayStates.LOADED } - - override fun use(shader: Shader, name: String) { - shader.use() - + override fun activate() { for ((index, textureId) in textureIds.withIndex()) { if (textureId == -1) { continue } glActiveTexture(GL_TEXTURE0 + index) glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) + } + } + + override fun use(shader: Shader, name: String) { + shader.use() + activate() + + for ((index, textureId) in textureIds.withIndex()) { + if (textureId == -1) { + continue + } + + glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) shader.setTexture("$name[$index]", index) } } 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 c503ce0a5..9ea325e47 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 @@ -14,6 +14,7 @@ package de.bixilon.minosoft.gui.rendering.system.opengl.texture.dynamic import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture +import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState import java.util.* import java.util.concurrent.atomic.AtomicInteger @@ -21,13 +22,23 @@ class OpenGLDynamicTexture( override val uuid: UUID, shaderId: Int, ) : DynamicTexture { + override var onStateChange: (() -> Unit)? = null override val usages = AtomicInteger() + override var state: DynamicTextureState = DynamicTextureState.WAITING + set(value) { + field = value + onStateChange?.invoke() + } - override val shaderId: Int = shaderId + override var shaderId: Int = shaderId get() { - if (usages.get() == 0) { + if (usages.get() == 0 || state == DynamicTextureState.UNLOADED) { throw IllegalStateException("Texture was eventually garbage collected") } return field } + + override fun toString(): String { + return uuid.toString() + } } 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 fe4762276..196688f5d 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 @@ -14,11 +14,13 @@ package de.bixilon.minosoft.gui.rendering.system.opengl.texture.dynamic import de.bixilon.kotlinglm.vec2.Vec2i +import de.bixilon.kutil.concurrent.pool.DefaultThreadPool import de.bixilon.kutil.latch.CountUpAndDownLatch import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureArray +import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil import org.lwjgl.opengl.GL11.* import org.lwjgl.opengl.GL12.glTexImage3D @@ -54,6 +56,18 @@ class OpenGLDynamicTextureArray( return pushBuffer(identifier) { ByteBuffer.wrap(data()) } } + private fun load(texture: OpenGLDynamicTexture, index: Int, mipmaps: Array) { + glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) + + for ((level, mipmap) in mipmaps.withIndex()) { + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, index, resolution shr level, resolution shr level, 1, GL_RGBA, GL_UNSIGNED_BYTE, mipmap) + } + + texture.state = DynamicTextureState.LOADED + renderWindow.textureManager.staticTextures.activate() + } + + @Synchronized override fun pushBuffer(identifier: UUID, data: () -> ByteBuffer): OpenGLDynamicTexture { check(textureId >= 0) { "Dynamic texture array not yet initialized!" } cleanup() @@ -62,20 +76,19 @@ class OpenGLDynamicTextureArray( 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 = getNextIndex() + val texture = OpenGLDynamicTexture(identifier, createShaderIdentifier(index = index)) + textures[index] = texture + texture.state = DynamicTextureState.LOADING + DefaultThreadPool += { + val bytes = data() - glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) + check(bytes.limit() == resolution * resolution * 4) { "Texture must have a size of ${resolution}x${resolution}" } - for ((level, mipmap) in mipmaps.withIndex()) { - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, index, resolution shr level, resolution shr level, 1, GL_RGBA, GL_UNSIGNED_BYTE, mipmap) + val mipmaps = OpenGLTextureUtil.generateMipMaps(bytes, Vec2i(resolution, resolution)) + renderWindow.queue += { load(texture, index, mipmaps) } } - - return OpenGLDynamicTexture(identifier, createShaderIdentifier(index = index)) + return texture } private fun createShaderIdentifier(array: Int = this.index, index: Int): Int { @@ -96,11 +109,16 @@ class OpenGLDynamicTextureArray( this.textureId = textureId } + override fun activate() { + glActiveTexture(GL_TEXTURE0 + index) + glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) + } + override fun use(shader: Shader, name: String) { shader.use() - glActiveTexture(GL_TEXTURE0 + index) - glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) + activate() + shader.setTexture("$name[$index]", index) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt index a83a1e3a6..2fdf6e760 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt @@ -648,6 +648,7 @@ class WorldRenderer( } override fun prepareDraw() { + renderWindow.textureManager.staticTextures.use(shader) if (clearVisibleNextFrame) { visible.clear() clearVisibleNextFrame = false diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/tab/TabListS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/tab/TabListS2CP.kt index 2502f36b5..0f52dfb80 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/tab/TabListS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/tab/TabListS2CP.kt @@ -102,7 +102,11 @@ class TabListS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { // item not yet created return@run null } - val item = TabListItem(name = data.name) + val item = if (entity === connection.player) { + connection.player.tabListItem + } else { + TabListItem(name = data.name) + } connection.tabList.tabListItemsByUUID[uuid] = item connection.tabList.tabListItemsByName[data.name] = item