mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-12 08:58:02 -04:00
rework some mipmapping
This commit is contained in:
parent
66846d9abd
commit
31225196ee
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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<ResourceLocation, Texture> = 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
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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))
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<ResourceLocation, Texture> = mutableMapOf()
|
||||
protected val other: MutableSet<Texture> = 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)
|
||||
}
|
||||
|
@ -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<TextureBuffer> = OpenGLTextureUtil.generateMipMaps(buffer)
|
||||
val mipmaps: Array<TextureBuffer> = generate(levels)
|
||||
|
||||
override fun collect(): Array<TextureBuffer> = mipmaps
|
||||
|
||||
|
||||
fun generate(levels: Int): Array<TextureBuffer> {
|
||||
val images: MutableList<TextureBuffer> = 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()
|
||||
}
|
||||
}
|
||||
|
@ -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<WeakReference<DynamicTexture>?> = arrayOfNulls(initialSize)
|
||||
protected val shaders: MutableSet<NativeShader> = 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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<ResourceLocation, Texture> = mutableMapOf()
|
||||
private val otherTextures: MutableSet<Texture> = 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<MutableList<Texture>>(TEXTURE_RESOLUTION_ID_MAP.size) { mutableListOf() }
|
||||
private val lastTextureId = IntArray(TEXTURE_RESOLUTION_ID_MAP.size)
|
||||
@ -68,46 +55,6 @@ class OpenGLTextureArray(
|
||||
context.system.unsafeCast<OpenGLRenderSystem>().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<Texture>) {
|
||||
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<Texture>): 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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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<TextureBuffer> {
|
||||
val images: MutableList<TextureBuffer> = 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
|
||||
|
@ -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?)
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user