mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-19 04:15:14 -04:00
load dynamic textures async, fix some tab list bugs
This commit is contained in:
parent
e2df230da4
commit
e7f3891cc4
@ -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.player.properties.PlayerProperties
|
||||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||||
@JsonSubTypes(
|
@JsonSubTypes(
|
||||||
@ -42,6 +43,7 @@ abstract class Account(
|
|||||||
abstract val properties: PlayerProperties?
|
abstract val properties: PlayerProperties?
|
||||||
@get:JsonIgnore @set:JsonIgnore open var state: AccountStates by watched(AccountStates.UNCHECKED)
|
@get:JsonIgnore @set:JsonIgnore open var state: AccountStates by watched(AccountStates.UNCHECKED)
|
||||||
@get:JsonIgnore open var error: Throwable? by watched(null)
|
@get:JsonIgnore open var error: Throwable? by watched(null)
|
||||||
|
abstract val uuid: UUID
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
|
@ -32,7 +32,7 @@ import java.net.ConnectException
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class MicrosoftAccount(
|
class MicrosoftAccount(
|
||||||
val uuid: UUID,
|
override val uuid: UUID,
|
||||||
username: String,
|
username: String,
|
||||||
@field:JsonProperty private var msa: MicrosoftTokens,
|
@field:JsonProperty private var msa: MicrosoftTokens,
|
||||||
@field:JsonProperty private var minecraft: MinecraftTokens,
|
@field:JsonProperty private var minecraft: MinecraftTokens,
|
||||||
|
@ -38,7 +38,7 @@ import java.util.*
|
|||||||
class MojangAccount(
|
class MojangAccount(
|
||||||
override val id: String,
|
override val id: String,
|
||||||
username: String,
|
username: String,
|
||||||
val uuid: UUID,
|
override val uuid: UUID,
|
||||||
val email: String,
|
val email: String,
|
||||||
@field:JsonProperty private var accessToken: String,
|
@field:JsonProperty private var accessToken: String,
|
||||||
override val properties: PlayerProperties?,
|
override val properties: PlayerProperties?,
|
||||||
|
@ -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.CompanionResourceLocation
|
||||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class OfflineAccount(username: String) : Account(username) {
|
class OfflineAccount(username: String) : Account(username) {
|
||||||
override val id: String = username
|
override val id: String = username
|
||||||
|
override val uuid: UUID = UUID("OfflinePlayer:$username".hashCode().toLong(), 0L) // ToDo
|
||||||
override val type: ResourceLocation = RESOURCE_LOCATION
|
override val type: ResourceLocation = RESOURCE_LOCATION
|
||||||
override var state: AccountStates
|
override var state: AccountStates
|
||||||
get() = AccountStates.WORKING
|
get() = AccountStates.WORKING
|
||||||
|
@ -22,7 +22,7 @@ import de.bixilon.minosoft.data.player.properties.textures.PlayerTextures
|
|||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PlayerProperties(
|
data class PlayerProperties(
|
||||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
val textures: PlayerTextures? = null,
|
val textures: PlayerTextures? = null,
|
||||||
) {
|
) {
|
||||||
|
@ -17,6 +17,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore
|
|||||||
import de.bixilon.kutil.url.URLUtil.checkWeb
|
import de.bixilon.kutil.url.URLUtil.checkWeb
|
||||||
import de.bixilon.minosoft.assets.util.FileAssetsUtil
|
import de.bixilon.minosoft.assets.util.FileAssetsUtil
|
||||||
import de.bixilon.minosoft.assets.util.FileUtil
|
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.net.URL
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -33,7 +36,9 @@ open class PlayerTexture(
|
|||||||
check(urlMatches(url, ALLOWED_DOMAINS) && !urlMatches(url, BLOCKED_DOMAINS)) { "URL hostname is not allowed!" }
|
check(urlMatches(url, ALLOWED_DOMAINS) && !urlMatches(url, BLOCKED_DOMAINS)) { "URL hostname is not allowed!" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
fun read(): ByteArray {
|
fun read(): ByteArray {
|
||||||
|
this.data?.let { return it }
|
||||||
val sha256 = when (url.host) {
|
val sha256 = when (url.host) {
|
||||||
"textures.minecraft.net" -> url.file.split("/").last()
|
"textures.minecraft.net" -> url.file.split("/").last()
|
||||||
else -> TODO("Can not get texture identifier!")
|
else -> TODO("Can not get texture identifier!")
|
||||||
@ -50,6 +55,7 @@ open class PlayerTexture(
|
|||||||
throw IllegalStateException("Texture is too big!")
|
throw IllegalStateException("Texture is too big!")
|
||||||
}
|
}
|
||||||
val data = FileAssetsUtil.saveAndGet(input)
|
val data = FileAssetsUtil.saveAndGet(input)
|
||||||
|
Log.log(LogMessageType.ASSETS, LogLevels.VERBOSE) { "Downloaded skin ($url)" }
|
||||||
return data.second
|
return data.second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import de.bixilon.minosoft.util.YggdrasilUtil
|
|||||||
import de.bixilon.minosoft.util.json.Jackson
|
import de.bixilon.minosoft.util.json.Jackson
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PlayerTextures(
|
data class PlayerTextures(
|
||||||
@JsonInclude(JsonInclude.Include.NON_EMPTY) val name: String?,
|
@JsonInclude(JsonInclude.Include.NON_EMPTY) val name: String?,
|
||||||
@JsonInclude(JsonInclude.Include.NON_EMPTY) val uuid: UUID?,
|
@JsonInclude(JsonInclude.Include.NON_EMPTY) val uuid: UUID?,
|
||||||
@JsonInclude(JsonInclude.Include.NON_EMPTY) val date: Date?,
|
@JsonInclude(JsonInclude.Include.NON_EMPTY) val date: Date?,
|
||||||
|
@ -211,6 +211,9 @@ class RenderWindow(
|
|||||||
|
|
||||||
connection.fireEvent(ResizeWindowEvent(previousSize = Vec2i(0, 0), size = window.size))
|
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()}" }
|
Log.log(LogMessageType.RENDERING_LOADING) { "Rendering is fully prepared in ${stopwatch.totalTime()}" }
|
||||||
initialized = true
|
initialized = true
|
||||||
latch.dec()
|
latch.dec()
|
||||||
|
@ -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.GUIMesh
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
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.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.Vec2Util.EMPTY
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.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),
|
uvEnd: Vec2 = Vec2(1.0f, 1.0f),
|
||||||
size: Vec2i = Vec2i.EMPTY,
|
size: Vec2i = Vec2i.EMPTY,
|
||||||
tint: RGBColor = ChatColors.WHITE,
|
tint: RGBColor = ChatColors.WHITE,
|
||||||
|
parent: Element? = null,
|
||||||
) : Element(guiRenderer, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6) {
|
) : Element(guiRenderer, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6) {
|
||||||
|
|
||||||
var texture: DynamicTexture? = texture
|
var texture: DynamicTexture? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
field?.usages?.decrementAndGet()
|
field?.usages?.decrementAndGet()
|
||||||
|
field?.onStateChange = null
|
||||||
value?.usages?.incrementAndGet()
|
value?.usages?.incrementAndGet()
|
||||||
|
value?.onStateChange = { forceApply() }
|
||||||
field = value
|
field = value
|
||||||
cacheUpToDate = false
|
cacheUpToDate = false
|
||||||
}
|
}
|
||||||
@ -74,11 +79,20 @@ open class DynamicImageElement(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
this.size = size
|
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?) {
|
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
|
override fun forceSilentApply() = Unit
|
||||||
|
@ -49,7 +49,7 @@ class TabListEntryElement(
|
|||||||
|
|
||||||
private val background: ColorElement
|
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 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)
|
private val nameElement = TextElement(guiRenderer, "", background = false, parent = this)
|
||||||
@ -86,7 +86,7 @@ class TabListEntryElement(
|
|||||||
override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
|
override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
|
||||||
background.render(offset, consumer, options)
|
background.render(offset, consumer, options)
|
||||||
skinElement.render(offset + Vec2i(PADDING, PADDING), 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)
|
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
|
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
|
background.size = size
|
||||||
cacheUpToDate = false
|
cacheUpToDate = false
|
||||||
}
|
}
|
||||||
|
@ -19,5 +19,6 @@ import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader
|
|||||||
interface TextureArray {
|
interface TextureArray {
|
||||||
fun load(latch: CountUpAndDownLatch)
|
fun load(latch: CountUpAndDownLatch)
|
||||||
|
|
||||||
|
fun activate()
|
||||||
fun use(shader: Shader, name: String = "uTextures")
|
fun use(shader: Shader, name: String = "uTextures")
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,9 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture
|
|||||||
|
|
||||||
import de.bixilon.kotlinglm.vec2.Vec2
|
import de.bixilon.kotlinglm.vec2.Vec2
|
||||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
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.PlayerTexture.Companion.isSteve
|
||||||
import de.bixilon.minosoft.data.player.properties.textures.PlayerTextures
|
|
||||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.atlas.TextureLikeTexture
|
import de.bixilon.minosoft.gui.rendering.gui.atlas.TextureLikeTexture
|
||||||
@ -56,14 +56,25 @@ abstract class TextureManager {
|
|||||||
|
|
||||||
fun loadDefaultSkins(connection: PlayConnection) {
|
fun loadDefaultSkins(connection: PlayConnection) {
|
||||||
// ToDo: For testing purposes only, they will be moved to static textures
|
// 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 }
|
steveTexture = dynamicTextures.pushBuffer(UUID(0L, 0L)) { connection.assetsManager["minecraft:entity/steve".toResourceLocation().texture()].readTexture().second }.apply { usages.incrementAndGet() }
|
||||||
alexTexture = dynamicTextures.pushBuffer("3780a46b-a725-4b22-8366-01056c698386".toUUID()) { connection.assetsManager["minecraft:entity/alex".toResourceLocation().texture()].readTexture().second }
|
alexTexture = dynamicTextures.pushBuffer(UUID(1L, 0L)) { connection.assetsManager["minecraft:entity/alex".toResourceLocation().texture()].readTexture().second }.apply { usages.incrementAndGet() }
|
||||||
skin = getSkin(connection.player.uuid ?: UUID.randomUUID(), connection.account.properties?.textures)
|
skin = getSkin(connection.account.uuid, connection.account.properties).apply { usages.incrementAndGet() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getSkin(uuid: UUID, properties: PlayerTextures?): DynamicTexture {
|
fun getSkin(uuid: UUID, properties: PlayerProperties?): DynamicTexture {
|
||||||
properties?.skin?.let { return dynamicTextures.pushRawArray(uuid) { it.read() } }
|
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()) {
|
if (uuid.isSteve()) {
|
||||||
return steveTexture
|
return steveTexture
|
||||||
}
|
}
|
||||||
|
@ -20,4 +20,8 @@ import java.util.concurrent.atomic.AtomicInteger
|
|||||||
interface DynamicTexture : ShaderIdentifiable {
|
interface DynamicTexture : ShaderIdentifiable {
|
||||||
val uuid: UUID
|
val uuid: UUID
|
||||||
val usages: AtomicInteger
|
val usages: AtomicInteger
|
||||||
|
|
||||||
|
val state: DynamicTextureState
|
||||||
|
|
||||||
|
var onStateChange: (() -> Unit)?
|
||||||
}
|
}
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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,
|
||||||
|
;
|
||||||
|
}
|
@ -191,16 +191,26 @@ class OpenGLTextureArray(
|
|||||||
state = TextureArrayStates.LOADED
|
state = TextureArrayStates.LOADED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun activate() {
|
||||||
override fun use(shader: Shader, name: String) {
|
|
||||||
shader.use()
|
|
||||||
|
|
||||||
for ((index, textureId) in textureIds.withIndex()) {
|
for ((index, textureId) in textureIds.withIndex()) {
|
||||||
if (textureId == -1) {
|
if (textureId == -1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
glActiveTexture(GL_TEXTURE0 + index)
|
glActiveTexture(GL_TEXTURE0 + index)
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, textureId)
|
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)
|
shader.setTexture("$name[$index]", index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
package de.bixilon.minosoft.gui.rendering.system.opengl.texture.dynamic
|
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.DynamicTexture
|
||||||
|
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
@ -21,13 +22,23 @@ class OpenGLDynamicTexture(
|
|||||||
override val uuid: UUID,
|
override val uuid: UUID,
|
||||||
shaderId: Int,
|
shaderId: Int,
|
||||||
) : DynamicTexture {
|
) : DynamicTexture {
|
||||||
|
override var onStateChange: (() -> Unit)? = null
|
||||||
override val usages = AtomicInteger()
|
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() {
|
get() {
|
||||||
if (usages.get() == 0) {
|
if (usages.get() == 0 || state == DynamicTextureState.UNLOADED) {
|
||||||
throw IllegalStateException("Texture was eventually garbage collected")
|
throw IllegalStateException("Texture was eventually garbage collected")
|
||||||
}
|
}
|
||||||
return field
|
return field
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return uuid.toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,13 @@
|
|||||||
package de.bixilon.minosoft.gui.rendering.system.opengl.texture.dynamic
|
package de.bixilon.minosoft.gui.rendering.system.opengl.texture.dynamic
|
||||||
|
|
||||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||||
|
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
|
||||||
import de.bixilon.kutil.latch.CountUpAndDownLatch
|
import de.bixilon.kutil.latch.CountUpAndDownLatch
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
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.shader.Shader
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture
|
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.DynamicTextureArray
|
||||||
|
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState
|
||||||
import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil
|
import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil
|
||||||
import org.lwjgl.opengl.GL11.*
|
import org.lwjgl.opengl.GL11.*
|
||||||
import org.lwjgl.opengl.GL12.glTexImage3D
|
import org.lwjgl.opengl.GL12.glTexImage3D
|
||||||
@ -54,6 +56,18 @@ class OpenGLDynamicTextureArray(
|
|||||||
return pushBuffer(identifier) { ByteBuffer.wrap(data()) }
|
return pushBuffer(identifier) { ByteBuffer.wrap(data()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun load(texture: OpenGLDynamicTexture, index: Int, mipmaps: Array<ByteBuffer>) {
|
||||||
|
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 {
|
override fun pushBuffer(identifier: UUID, data: () -> ByteBuffer): OpenGLDynamicTexture {
|
||||||
check(textureId >= 0) { "Dynamic texture array not yet initialized!" }
|
check(textureId >= 0) { "Dynamic texture array not yet initialized!" }
|
||||||
cleanup()
|
cleanup()
|
||||||
@ -62,20 +76,19 @@ class OpenGLDynamicTextureArray(
|
|||||||
return texture
|
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 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()) {
|
val mipmaps = OpenGLTextureUtil.generateMipMaps(bytes, Vec2i(resolution, resolution))
|
||||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, index, resolution shr level, resolution shr level, 1, GL_RGBA, GL_UNSIGNED_BYTE, mipmap)
|
renderWindow.queue += { load(texture, index, mipmaps) }
|
||||||
}
|
}
|
||||||
|
return texture
|
||||||
return OpenGLDynamicTexture(identifier, createShaderIdentifier(index = index))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createShaderIdentifier(array: Int = this.index, index: Int): Int {
|
private fun createShaderIdentifier(array: Int = this.index, index: Int): Int {
|
||||||
@ -96,11 +109,16 @@ class OpenGLDynamicTextureArray(
|
|||||||
this.textureId = textureId
|
this.textureId = textureId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun activate() {
|
||||||
|
glActiveTexture(GL_TEXTURE0 + index)
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, textureId)
|
||||||
|
}
|
||||||
|
|
||||||
override fun use(shader: Shader, name: String) {
|
override fun use(shader: Shader, name: String) {
|
||||||
shader.use()
|
shader.use()
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + index)
|
activate()
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, textureId)
|
|
||||||
shader.setTexture("$name[$index]", index)
|
shader.setTexture("$name[$index]", index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,6 +648,7 @@ class WorldRenderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun prepareDraw() {
|
override fun prepareDraw() {
|
||||||
|
renderWindow.textureManager.staticTextures.use(shader)
|
||||||
if (clearVisibleNextFrame) {
|
if (clearVisibleNextFrame) {
|
||||||
visible.clear()
|
visible.clear()
|
||||||
clearVisibleNextFrame = false
|
clearVisibleNextFrame = false
|
||||||
|
@ -102,7 +102,11 @@ class TabListS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
|
|||||||
// item not yet created
|
// item not yet created
|
||||||
return@run null
|
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.tabListItemsByUUID[uuid] = item
|
||||||
connection.tabList.tabListItemsByName[data.name] = item
|
connection.tabList.tabListItemsByName[data.name] = item
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user