From 31225196ee6cf635db61a247dba78a73a925af50 Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Sat, 25 Nov 2023 19:46:00 +0100 Subject: [PATCH] rework some mipmapping --- .../models/baked/BakedModelTestUtil.kt | 2 +- .../dummy/texture/DummyDynamicTextureArray.kt | 2 +- .../dummy/texture/DummyStaticTextureArray.kt | 28 +------ .../system/dummy/texture/DummyTexture.kt | 2 +- .../dummy/texture/DummyTextureManager.kt | 2 +- .../profiles/rendering/RenderingProfile.kt | 2 + .../profiles/rendering/textures/TexturesC.kt | 25 ++++++ .../types/unicode/unihex/UnifontTexture.kt | 2 +- .../gui/atlas/textures/AtlasTexture.kt | 2 +- .../base/texture/array/StaticTextureArray.kt | 78 ++++++++++++++++-- .../base/texture/data/MipmapTextureData.kt | 21 ++++- .../texture/dynamic/DynamicTextureArray.kt | 3 +- .../base/texture/sprite/SpriteTexture.kt | 4 +- .../system/base/texture/texture/Texture.kt | 7 +- .../base/texture/texture/file/PNGTexture.kt | 5 +- .../texture/texture/memory/MemoryTexture.kt | 2 +- .../opengl/texture/OpenGLTextureArray.kt | 80 ++++--------------- .../opengl/texture/OpenGLTextureManager.kt | 5 +- .../opengl/texture/OpenGLTextureUtil.kt | 69 +--------------- .../dynamic/OpenGLDynamicTextureArray.kt | 7 +- 20 files changed, 162 insertions(+), 186 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/config/profile/profiles/rendering/textures/TexturesC.kt diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/BakedModelTestUtil.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/BakedModelTestUtil.kt index 1f9330488..92005c4ee 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/BakedModelTestUtil.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/BakedModelTestUtil.kt @@ -37,7 +37,7 @@ object BakedModelTestUtil { private val connection by lazy { createConnection() } private val rendering by lazy { val rendering = Rendering(connection) - rendering.context.textures::debugTexture.forceSet(MemoryTexture(Vec2i.EMPTY_INSTANCE, buffer = RGBA8Buffer(Vec2i(0, 0)))) + rendering.context.textures::debugTexture.forceSet(MemoryTexture(Vec2i.EMPTY_INSTANCE, mipmaps = 0, buffer = RGBA8Buffer(Vec2i(0, 0)))) return@lazy rendering } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyDynamicTextureArray.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyDynamicTextureArray.kt index 971c27d75..d302ebfcb 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyDynamicTextureArray.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyDynamicTextureArray.kt @@ -18,7 +18,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.shader.NativeShader import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureArray -class DummyDynamicTextureArray(context: RenderContext) : DynamicTextureArray(context, 1) { +class DummyDynamicTextureArray(context: RenderContext) : DynamicTextureArray(context, 1, 0) { override fun createTexture(identifier: Any, index: Int) = DummyDynamicTexture override fun unload() = Unit diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyStaticTextureArray.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyStaticTextureArray.kt index ba98dfc33..7bd0a5f3d 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyStaticTextureArray.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyStaticTextureArray.kt @@ -13,34 +13,16 @@ package de.bixilon.minosoft.gui.rendering.system.dummy.texture -import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf import de.bixilon.kutil.latch.AbstractLatch -import de.bixilon.minosoft.data.registries.identified.ResourceLocation -import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem +import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.system.base.shader.NativeShader import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates import de.bixilon.minosoft.gui.rendering.system.base.texture.array.StaticTextureArray -import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayStates -import de.bixilon.minosoft.gui.rendering.system.base.texture.sprite.SpriteAnimator -import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture -class DummyStaticTextureArray(renderSystem: RenderSystem) : StaticTextureArray { - private val textures: MutableMap = synchronizedMapOf() - override val animator: SpriteAnimator = SpriteAnimator(renderSystem) - override val state: TextureArrayStates = TextureArrayStates.DECLARED - - override fun get(resourceLocation: ResourceLocation): Texture? = textures[resourceLocation] - - override fun pushTexture(texture: Texture) { - TODO("Not yet implemented") - } - - override fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean, properties: Boolean, default: (mipmaps: Boolean) -> Texture): Texture { - return textures.getOrPut(resourceLocation) { DummyTexture() } - } +class DummyStaticTextureArray(context: RenderContext) : StaticTextureArray(context, false, 0) { override fun load(latch: AbstractLatch) { - for (texture in textures.values) { + for (texture in this.named.values) { (texture as DummyTexture).state = TextureStates.LOADED } } @@ -49,8 +31,6 @@ class DummyStaticTextureArray(renderSystem: RenderSystem) : StaticTextureArray { animator.init() } - override fun activate() { - } - + override fun activate() = Unit override fun use(shader: NativeShader, name: String) = Unit } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyTexture.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyTexture.kt index 8fb76bf43..640b629a8 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyTexture.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyTexture.kt @@ -33,7 +33,7 @@ class DummyTexture : Texture { override var properties: ImageProperties = ImageProperties() override var renderData: TextureRenderData = DummyTextureRenderData override lateinit var data: TextureData - override var mipmaps: Boolean = false + override val mipmaps: Int get() = 0 override fun load(context: RenderContext) { data = TextureData(RGBA8Buffer(size)) diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyTextureManager.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyTextureManager.kt index a2ddef28c..689d70255 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyTextureManager.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/system/dummy/texture/DummyTextureManager.kt @@ -20,5 +20,5 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicText class DummyTextureManager(val context: RenderContext) : TextureManager() { override val dynamicTextures: DynamicTextureArray = DummyDynamicTextureArray(context) - override val staticTextures: StaticTextureArray = DummyStaticTextureArray(context.system) + override val staticTextures: StaticTextureArray = DummyStaticTextureArray(context) } diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/rendering/RenderingProfile.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/rendering/RenderingProfile.kt index 47c58c147..106a4e395 100644 --- a/src/main/java/de/bixilon/minosoft/config/profile/profiles/rendering/RenderingProfile.kt +++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/rendering/RenderingProfile.kt @@ -27,6 +27,7 @@ import de.bixilon.minosoft.config.profile.profiles.rendering.movement.MovementC import de.bixilon.minosoft.config.profile.profiles.rendering.overlay.OverlayC import de.bixilon.minosoft.config.profile.profiles.rendering.performance.PerformanceC import de.bixilon.minosoft.config.profile.profiles.rendering.sky.SkyC +import de.bixilon.minosoft.config.profile.profiles.rendering.textures.TexturesC import de.bixilon.minosoft.config.profile.storage.ProfileStorage import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft import org.kordamp.ikonli.Ikon @@ -51,6 +52,7 @@ class RenderingProfile( val performance = PerformanceC(this) val overlay = OverlayC(this) val sky = SkyC(this) + val textures = TexturesC(this) override fun toString(): String { diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/rendering/textures/TexturesC.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/rendering/textures/TexturesC.kt new file mode 100644 index 000000000..8ada1c9e9 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/rendering/textures/TexturesC.kt @@ -0,0 +1,25 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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.config.profile.profiles.rendering.textures + +import de.bixilon.minosoft.config.profile.delegate.primitive.IntDelegate +import de.bixilon.minosoft.config.profile.profiles.rendering.RenderingProfile + +class TexturesC(profile: RenderingProfile) { + + /** + * Weather to use mipmaps for all static textures + */ + var mipmaps by IntDelegate(profile, 4, arrayOf(0..4)) +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/unihex/UnifontTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/unihex/UnifontTexture.kt index f8ff1d19f..74a6d4f65 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/unihex/UnifontTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/unihex/UnifontTexture.kt @@ -36,7 +36,7 @@ class UnifontTexture( override val size: Vec2i = Vec2i(resolution) private val pixel = 1.0f / size.x override val transparency: TextureTransparencies = TextureTransparencies.TRANSPARENT - override val mipmaps: Boolean get() = false + override val mipmaps: Int get() = 0 override lateinit var array: TextureArrayProperties override lateinit var renderData: TextureRenderData diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/textures/AtlasTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/textures/AtlasTexture.kt index a7d451667..076fdafff 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/textures/AtlasTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/textures/AtlasTexture.kt @@ -30,7 +30,7 @@ class AtlasTexture( override val size: Vec2i, ) : Texture { override val transparency: TextureTransparencies = TextureTransparencies.TRANSLUCENT - override val mipmaps: Boolean get() = false + override val mipmaps: Int get() = 0 private val pixel = Vec2(1.0f) / size override lateinit var array: TextureArrayProperties diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/StaticTextureArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/StaticTextureArray.kt index f1fc4e492..0c466cdee 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/StaticTextureArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/StaticTextureArray.kt @@ -13,21 +13,85 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture.array +import de.bixilon.kutil.concurrent.lock.simple.SimpleLock +import de.bixilon.kutil.concurrent.pool.DefaultThreadPool +import de.bixilon.kutil.concurrent.pool.runnable.ForcePooledRunnable import de.bixilon.kutil.latch.AbstractLatch +import de.bixilon.minosoft.assets.util.InputStreamUtil.readAsString import de.bixilon.minosoft.data.registries.identified.ResourceLocation +import de.bixilon.minosoft.gui.rendering.RenderContext +import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates import de.bixilon.minosoft.gui.rendering.system.base.texture.sprite.SpriteAnimator +import de.bixilon.minosoft.gui.rendering.system.base.texture.sprite.SpriteTexture import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.file.PNGTexture +import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties +import de.bixilon.minosoft.util.KUtil.toResourceLocation +import de.bixilon.minosoft.util.json.Jackson -interface StaticTextureArray : TextureArray { - val animator: SpriteAnimator - val state: TextureArrayStates +abstract class StaticTextureArray( + val context: RenderContext, + val async: Boolean, + val mipmaps: Int, +) : TextureArray { + protected val named: MutableMap = mutableMapOf() + protected val other: MutableSet = mutableSetOf() + private val lock = SimpleLock() + + val animator = SpriteAnimator(context.system) + var state: TextureArrayStates = TextureArrayStates.DECLARED + protected set + + + operator fun get(resourceLocation: ResourceLocation): Texture? { + lock.acquire() + val texture = this.named[resourceLocation] + lock.release() + return texture + } - operator fun get(resourceLocation: ResourceLocation): Texture? operator fun plusAssign(texture: Texture) = pushTexture(texture) - fun pushTexture(texture: Texture) - fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean = true, properties: Boolean = true, default: (mipmaps: Boolean) -> Texture = { PNGTexture(resourceLocation, mipmaps = it) }): Texture - fun load(latch: AbstractLatch) + fun pushTexture(texture: Texture) { + lock.lock() + other += texture + lock.unlock() + if (texture.state != TextureStates.LOADED && async) { + DefaultThreadPool += ForcePooledRunnable { texture.load(context) } + } + } + + fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean = true, properties: Boolean = true, factory: (mipmaps: Int) -> Texture = { PNGTexture(resourceLocation, mipmaps = it) }): Texture { + lock.lock() + named[resourceLocation]?.let { lock.unlock(); return it } + + // load .mcmeta + val properties = if (properties) readImageProperties(resourceLocation) ?: ImageProperties.DEFAULT else ImageProperties.DEFAULT // TODO: That kills performance + val default = factory.invoke(if (mipmaps) this.mipmaps else 0) + + val texture = if (properties.animation == null) default else SpriteTexture(default) + + texture.properties = properties + named[resourceLocation] = texture + lock.unlock() + if (async) { + DefaultThreadPool += ForcePooledRunnable { texture.load(context) } + } + + return texture + } + + private fun readImageProperties(texture: ResourceLocation): ImageProperties? { + try { + val data = context.connection.assetsManager.getOrNull("$texture.mcmeta".toResourceLocation())?.readAsString() ?: return null + return Jackson.MAPPER.readValue(data, ImageProperties::class.java) + } catch (error: Throwable) { + error.printStackTrace() + } + return null + } + + + abstract fun load(latch: AbstractLatch) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/data/MipmapTextureData.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/data/MipmapTextureData.kt index c8847bf07..32f0f4858 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/data/MipmapTextureData.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/data/MipmapTextureData.kt @@ -14,12 +14,29 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture.data import de.bixilon.minosoft.gui.rendering.system.base.texture.data.buffer.TextureBuffer -import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil open class MipmapTextureData( buffer: TextureBuffer, + levels: Int, ) : TextureData(buffer) { - val mipmaps: Array = OpenGLTextureUtil.generateMipMaps(buffer) + val mipmaps: Array = generate(levels) override fun collect(): Array = mipmaps + + + fun generate(levels: Int): Array { + val images: MutableList = mutableListOf(buffer) + + var data = buffer + for (i in 0 until levels) { + val size = data.size shr 1 + if (size.x <= 0 || size.y <= 0) { + break + } + data = data.mipmap() + images += data + } + + return images.toTypedArray() + } } 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 e7160b3ae..b69aabc5a 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 @@ -30,6 +30,7 @@ import java.lang.ref.WeakReference abstract class DynamicTextureArray( val context: RenderContext, val initialSize: Int, + val mipmaps: Int, ) : TextureArray { protected var textures: Array?> = arrayOfNulls(initialSize) protected val shaders: MutableSet = mutableSetOf() @@ -71,7 +72,7 @@ abstract class DynamicTextureArray( private fun DynamicTexture.load(index: Int, creator: () -> TextureBuffer) { val buffer = creator.invoke() - this.data = MipmapTextureData(buffer) + this.data = MipmapTextureData(buffer, mipmaps) if (Thread.currentThread() == context.thread) { upload(index, this) } else { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/sprite/SpriteTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/sprite/SpriteTexture.kt index c66740bd4..cb0315300 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/sprite/SpriteTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/sprite/SpriteTexture.kt @@ -30,7 +30,7 @@ class SpriteTexture(private val original: Texture) : Texture { override var properties: ImageProperties by original::properties override var renderData: TextureRenderData by original::renderData override val transparency: TextureTransparencies by original::transparency - override var mipmaps: Boolean = true + override val mipmaps: Int get() = original.mipmaps override var state: TextureStates = TextureStates.DECLARED private set @@ -58,7 +58,7 @@ class SpriteTexture(private val original: Texture) : Texture { val buffer = original.create(size) buffer.put(original, Vec2i(0, size.y), Vec2i.EMPTY, size) - val splitTexture = MemoryTexture(size, mipmaps = true, buffer = buffer) + val splitTexture = MemoryTexture(size, mipmaps = this.original.mipmaps, buffer = buffer) splitTextures += splitTexture } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/Texture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/Texture.kt index 7395eb39c..8220eccfd 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/Texture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/Texture.kt @@ -35,7 +35,7 @@ interface Texture : ShaderTexture { var renderData: TextureRenderData var data: TextureData - val mipmaps: Boolean + val mipmaps: Int fun load(context: RenderContext) @@ -52,7 +52,8 @@ interface Texture : ShaderTexture { return renderData.transformUV(end) } - fun createData(mipmaps: Boolean = this.mipmaps, buffer: TextureBuffer): TextureData { - return if (mipmaps) MipmapTextureData(buffer) else TextureData(buffer) + fun createData(mipmaps: Int = this.mipmaps, buffer: TextureBuffer): TextureData { + if (mipmaps <= 0) return TextureData(buffer) + return MipmapTextureData(buffer, mipmaps) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/file/PNGTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/file/PNGTexture.kt index 4bfe07eab..eae57ae61 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/file/PNGTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/file/PNGTexture.kt @@ -20,7 +20,6 @@ import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayProperties -import de.bixilon.minosoft.gui.rendering.system.base.texture.data.MipmapTextureData import de.bixilon.minosoft.gui.rendering.system.base.texture.data.TextureData import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.TextureRenderData import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.readTexture @@ -33,7 +32,7 @@ import java.io.FileNotFoundException class PNGTexture( override val resourceLocation: ResourceLocation, - override var mipmaps: Boolean = true, + override var mipmaps: Int, ) : FileTexture { override lateinit var renderData: TextureRenderData @@ -66,7 +65,7 @@ class PNGTexture( } assetsManager[RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION].readTexture() } - val data = if (mipmaps) MipmapTextureData(buffer) else TextureData(buffer) + val data = createData(mipmaps, buffer) this.size = data.size transparency = TextureTransparencies.OPAQUE diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/memory/MemoryTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/memory/MemoryTexture.kt index 5a27b7457..0fe0a1d0c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/memory/MemoryTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/memory/MemoryTexture.kt @@ -27,7 +27,7 @@ import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties class MemoryTexture( override val size: Vec2i, override var properties: ImageProperties = ImageProperties(), - override var mipmaps: Boolean = true, + override var mipmaps: Int, buffer: TextureBuffer, ) : Texture { override lateinit var array: TextureArrayProperties 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 619752642..caf582fee 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 @@ -17,12 +17,9 @@ import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kutil.cast.CastUtil.unsafeCast import de.bixilon.kutil.concurrent.pool.DefaultThreadPool import de.bixilon.kutil.concurrent.pool.ThreadPool -import de.bixilon.kutil.concurrent.pool.runnable.ForcePooledRunnable import de.bixilon.kutil.concurrent.pool.runnable.SimplePoolRunnable import de.bixilon.kutil.latch.AbstractLatch import de.bixilon.kutil.latch.SimpleLatch -import de.bixilon.minosoft.assets.util.InputStreamUtil.readAsString -import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.system.base.shader.NativeShader import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates @@ -30,36 +27,26 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.array.StaticTexture import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayProperties import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayStates import de.bixilon.minosoft.gui.rendering.system.base.texture.data.TextureData -import de.bixilon.minosoft.gui.rendering.system.base.texture.sprite.SpriteAnimator import de.bixilon.minosoft.gui.rendering.system.base.texture.sprite.SpriteTexture import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil.glFormat import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil.glType import de.bixilon.minosoft.gui.rendering.textures.TextureAnimation -import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties -import de.bixilon.minosoft.util.KUtil.toResourceLocation -import de.bixilon.minosoft.util.json.Jackson import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogMessageType -import org.lwjgl.opengl.GL12.* -import org.lwjgl.opengl.GL13.GL_TEXTURE0 -import org.lwjgl.opengl.GL13.glActiveTexture +import org.lwjgl.opengl.GL13.* import org.lwjgl.opengl.GL30.GL_TEXTURE_2D_ARRAY import java.nio.ByteBuffer import java.util.concurrent.atomic.AtomicInteger class OpenGLTextureArray( - val context: RenderContext, - private val loadTexturesAsync: Boolean = true, -) : StaticTextureArray { - private val namedTextures: MutableMap = mutableMapOf() - private val otherTextures: MutableSet = mutableSetOf() + context: RenderContext, + async: Boolean, + mipmaps: Int, +) : StaticTextureArray(context, async, mipmaps) { private var textureIds = IntArray(TEXTURE_RESOLUTION_ID_MAP.size) { -1 } - override val animator = SpriteAnimator(context.system) - override var state: TextureArrayStates = TextureArrayStates.DECLARED - private set private val texturesByResolution = Array>(TEXTURE_RESOLUTION_ID_MAP.size) { mutableListOf() } private val lastTextureId = IntArray(TEXTURE_RESOLUTION_ID_MAP.size) @@ -68,46 +55,6 @@ class OpenGLTextureArray( context.system.unsafeCast().textureBindingIndex += TEXTURE_RESOLUTION_ID_MAP.size } - override fun get(resourceLocation: ResourceLocation): Texture? { - return this.namedTextures[resourceLocation] - } - - @Synchronized - override fun pushTexture(texture: Texture) { - otherTextures += texture - if (texture.state != TextureStates.LOADED && loadTexturesAsync) { - DefaultThreadPool += ForcePooledRunnable { texture.load(context) } - } - } - - @Synchronized - override fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean, properties: Boolean, default: (mipmaps: Boolean) -> Texture): Texture { - namedTextures[resourceLocation]?.let { return it } - - // load .mcmeta - val properties = if (properties) readImageProperties(resourceLocation) ?: ImageProperties.DEFAULT else ImageProperties.DEFAULT // TODO: That kills performance - - val texture = if (properties.animation == null) default(mipmaps) else SpriteTexture(default(false)) - - texture.properties = properties - namedTextures[resourceLocation] = texture - if (loadTexturesAsync) { - DefaultThreadPool += ForcePooledRunnable { texture.load(context) } - } - - return texture - } - - private fun readImageProperties(texture: ResourceLocation): ImageProperties? { - try { - val data = context.connection.assetsManager.getOrNull("$texture.mcmeta".toResourceLocation())?.readAsString() ?: return null - return Jackson.MAPPER.readValue(data, ImageProperties::class.java) - } catch (error: Throwable) { - error.printStackTrace() - } - return null - } - private fun preLoad(latch: AbstractLatch, textures: Collection) { for (texture in textures) { @@ -171,29 +118,30 @@ class OpenGLTextureArray( if (state == TextureArrayStates.LOADED || state == TextureArrayStates.PRE_LOADED) { return } - val preLoadLatch = SimpleLatch(namedTextures.size + otherTextures.size) - preLoad(preLoadLatch, namedTextures.values) - preLoad(preLoadLatch, otherTextures) + val preLoadLatch = SimpleLatch(named.size + other.size) + preLoad(preLoadLatch, named.values) + preLoad(preLoadLatch, other) preLoadLatch.await() val animationIndex = AtomicInteger() - preLoad(animationIndex, namedTextures.values) - preLoad(animationIndex, otherTextures) + preLoad(animationIndex, named.values) + preLoad(animationIndex, other) state = TextureArrayStates.PRE_LOADED } private fun loadSingleArray(resolution: Int, textures: List): Int { - val textureId = OpenGLTextureUtil.createTextureArray() + val textureId = OpenGLTextureUtil.createTextureArray(mipmaps) - for (level in 0 until OpenGLTextureUtil.MAX_MIPMAP_LEVELS) { + for (level in 0..mipmaps) { glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA8, resolution shr level, resolution shr level, textures.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?) } for (texture in textures) { val renderData = texture.renderData as OpenGLTextureData for ((level, buffer) in texture.data.collect().withIndex()) { + if (level > this.mipmaps) break buffer.data.flip() glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, renderData.index, buffer.size.x, buffer.size.y, 1, buffer.glFormat, buffer.glType, buffer.data) } @@ -214,7 +162,7 @@ class OpenGLTextureArray( textureIds[index] = loadSingleArray(TEXTURE_RESOLUTION_ID_MAP[index], textures) totalLayers += textures.size } - Log.log(LogMessageType.RENDERING, LogLevels.VERBOSE) { "Loaded ${namedTextures.size} textures containing ${animator.animations.size} animated ones, split into $totalLayers layers!" } + Log.log(LogMessageType.RENDERING, LogLevels.VERBOSE) { "Loaded ${named.size} textures containing ${animator.animations.size} animated ones, split into $totalLayers layers!" } animator.init() state = TextureArrayStates.LOADED diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureManager.kt index dda2a46d2..476218932 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureManager.kt @@ -21,6 +21,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicText import de.bixilon.minosoft.gui.rendering.system.opengl.texture.dynamic.OpenGLDynamicTextureArray class OpenGLTextureManager(val context: RenderContext) : TextureManager() { - override val staticTextures: StaticTextureArray = OpenGLTextureArray(context) - override val dynamicTextures: DynamicTextureArray = OpenGLDynamicTextureArray(context, context.system.unsafeCast(), resolution = 64) + private val mipmaps = context.connection.profiles.rendering.textures.mipmaps + override val staticTextures: StaticTextureArray = OpenGLTextureArray(context, true, mipmaps) + override val dynamicTextures: DynamicTextureArray = OpenGLDynamicTextureArray(context, context.system.unsafeCast(), resolution = 64, mipmaps = mipmaps) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureUtil.kt index 69832c0a5..02578efaf 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureUtil.kt @@ -13,90 +13,27 @@ package de.bixilon.minosoft.gui.rendering.system.opengl.texture -import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.gui.rendering.system.base.texture.data.buffer.RGB8Buffer import de.bixilon.minosoft.gui.rendering.system.base.texture.data.buffer.RGBA8Buffer import de.bixilon.minosoft.gui.rendering.system.base.texture.data.buffer.TextureBuffer -import example.jonathan2520.SRGBAverager -import org.lwjgl.BufferUtils import org.lwjgl.opengl.GL11.* import org.lwjgl.opengl.GL12.GL_TEXTURE_MAX_LEVEL import org.lwjgl.opengl.GL30.GL_TEXTURE_2D_ARRAY -import java.nio.ByteBuffer object OpenGLTextureUtil { - const val MAX_MIPMAP_LEVELS = 5 - - fun createTextureArray(): Int { + fun createTextureArray(mipmaps: Int): Int { val textureId = glGenTextures() glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT) glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT) - // glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST) - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR) + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, if (mipmaps == 0) GL_NEAREST else GL_NEAREST_MIPMAP_NEAREST) glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST) - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, MAX_MIPMAP_LEVELS - 1) + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, mipmaps) return textureId } - fun generateMipMaps(buffer: TextureBuffer): Array { - val images: MutableList = mutableListOf() - - images += buffer - - var data = buffer - for (i in 1 until MAX_MIPMAP_LEVELS) { - val size = Vec2i(buffer.size.x shr i, buffer.size.y shr i) - if (size.x <= 0 || size.y <= 0) { - break - } - data = data.mipmap() - images += data - } - - return images.toTypedArray() - } - - - private fun generateMipmap(origin: ByteBuffer, oldSize: Vec2i): ByteBuffer { - // No Vec2i: performance reasons - val oldSizeX = oldSize.x - val newSizeX = oldSizeX shr 1 - - val buffer = BufferUtils.createByteBuffer(origin.capacity() shr 1) - buffer.limit(buffer.capacity()) - - fun getRGB(x: Int, y: Int): Int { - return origin.getInt((y * oldSizeX + x) * 4) - } - - fun setRGB(x: Int, y: Int, color: Int) { - buffer.putInt((y * newSizeX + x) * 4, color) - } - - for (y in 0 until (oldSize.y shr 1)) { - for (x in 0 until newSizeX) { - val xOffset = x * 2 - val yOffset = y * 2 - - val output = SRGBAverager.average( - getRGB(xOffset + 0, yOffset + 0), - getRGB(xOffset + 1, yOffset + 0), - getRGB(xOffset + 0, yOffset + 1), - getRGB(xOffset + 1, yOffset + 1), - ) - - setRGB(x, y, output) - } - } - - origin.position(0) - buffer.position(0) - return buffer - } - val TextureBuffer.glFormat: Int get() = when (this) { is RGBA8Buffer -> GL_RGBA 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 bc058f7b0..17d3b2bd8 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 @@ -40,7 +40,8 @@ class OpenGLDynamicTextureArray( val index: Int = renderSystem.textureBindingIndex++, initialSize: Int = 32, val resolution: Int, -) : DynamicTextureArray(context, initialSize) { + mipmaps: Int, +) : DynamicTextureArray(context, initialSize, mipmaps) { private val empty = IntArray(resolution * resolution) { 0x00 } private var handle = -1 @@ -69,8 +70,8 @@ class OpenGLDynamicTextureArray( override fun upload() { if (handle >= 0) throw MemoryLeakException("Texture was not unloaded!") - val handle = OpenGLTextureUtil.createTextureArray() - for (level in 0 until OpenGLTextureUtil.MAX_MIPMAP_LEVELS) { + val handle = OpenGLTextureUtil.createTextureArray(mipmaps) + for (level in 0..mipmaps) { glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, resolution shr level, resolution shr level, textures.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?) }