From 35a9a08880c9fc766e9ede8d76b380a6522b2391 Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Sat, 25 Nov 2023 22:12:28 +0100 Subject: [PATCH] make opengl texture array implementation lighter Most of the functionality is actually not opengl specific, so abstract it --- .../rendering/models/baked/BakedFaceTest.kt | 2 +- .../dummy/texture/DummyStaticTextureArray.kt | 17 +- .../system/dummy/texture/DummyTexture.kt | 2 +- .../chunk/border/WorldBorderRenderer.kt | 2 +- .../storage/chest/DoubleChestRenderer.kt | 6 +- .../storage/chest/SingleChestRenderer.kt | 2 +- .../storage/shulker/ShulkerBoxRenderer.kt | 2 +- .../font/types/bitmap/BitmapCodeRenderer.kt | 5 +- .../font/types/bitmap/BitmapFontType.kt | 2 +- .../font/types/unicode/UnicodeCodeRenderer.kt | 9 +- .../unicode/legacy/LegacyUnicodeFontType.kt | 2 +- .../types/unicode/unihex/UnifontRasterizer.kt | 13 +- .../world/overlay/overlays/FireOverlay.kt | 2 +- .../overlays/simple/PowderSnowOverlay.kt | 2 +- .../overlay/overlays/simple/PumpkinOverlay.kt | 2 +- .../overlay/overlays/simple/WaterOverlay.kt | 2 +- .../overlays/simple/WorldBorderOverlay.kt | 2 +- .../overlays/weather/WeatherOverlay.kt | 6 +- .../gui/rendering/models/block/BlockModel.kt | 4 +- .../models/fluid/fluids/LavaFluidModel.kt | 4 +- .../models/fluid/fluids/WaterFluidModel.kt | 4 +- .../gui/rendering/models/item/ItemModel.kt | 2 +- .../rendering/particle/ParticleRenderer.kt | 2 +- .../rendering/skeletal/model/SkeletalModel.kt | 2 +- .../gui/rendering/sky/box/SkyboxRenderer.kt | 2 +- .../gui/rendering/sky/planet/MoonRenderer.kt | 7 +- .../gui/rendering/sky/planet/SunRenderer.kt | 2 +- .../system/base/texture/TextureManager.kt | 4 +- .../base/texture/array/StaticTextureArray.kt | 38 +++- .../texture/array/TextureArrayProperties.kt | 4 +- .../base/texture/array/TextureArrayStates.kt | 4 +- .../base/texture/sprite/SpriteTexture.kt | 1 + .../opengl/texture/OpenGLTextureArray.kt | 180 ++++++++---------- 33 files changed, 179 insertions(+), 161 deletions(-) diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/BakedFaceTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/BakedFaceTest.kt index 6d910ffb1..bc4582261 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/BakedFaceTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/BakedFaceTest.kt @@ -34,7 +34,7 @@ class BakedFaceTest { private fun texture(): Texture { val manager = BakedModelTestUtil.createTextureManager(texture) - return manager.staticTextures.createTexture(texture.toResourceLocation()) + return manager.staticTextures.create(texture.toResourceLocation()) } private fun singleMesh(): ChunkMesh { 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 7bd0a5f3d..43bd0843d 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,17 +13,22 @@ package de.bixilon.minosoft.gui.rendering.system.dummy.texture +import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kutil.latch.AbstractLatch +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 import de.bixilon.minosoft.gui.rendering.system.base.texture.array.StaticTextureArray +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture +import java.util.concurrent.atomic.AtomicInteger class DummyStaticTextureArray(context: RenderContext) : StaticTextureArray(context, false, 0) { - override fun load(latch: AbstractLatch) { - for (texture in this.named.values) { - (texture as DummyTexture).state = TextureStates.LOADED + override fun load(animationIndex: AtomicInteger, textures: Collection) { + for (texture in textures) { + if (texture !is DummyTexture) continue + texture.state = TextureStates.LOADED } } @@ -31,6 +36,12 @@ class DummyStaticTextureArray(context: RenderContext) : StaticTextureArray(conte animator.init() } + override fun create(resourceLocation: ResourceLocation, mipmaps: Boolean, properties: Boolean, factory: (mipmaps: Int) -> Texture): Texture { + return super.create(resourceLocation, mipmaps, properties) { DummyTexture() } + } + + override fun findResolution(size: Vec2i) = size + 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 640b629a8..3db6257d5 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 @@ -26,7 +26,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.TextureRend import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties class DummyTexture : Texture { - override var array = TextureArrayProperties(Vec2(), 1, Vec2()) + override var array = TextureArrayProperties(Vec2(), 1, 1.0f) override var state: TextureStates = TextureStates.DECLARED override var size: Vec2i = Vec2i(1, 1) override val transparency: TextureTransparencies get() = TextureTransparencies.OPAQUE diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/border/WorldBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/border/WorldBorderRenderer.kt index 77c2b5f8b..2e434c22d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/border/WorldBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/border/WorldBorderRenderer.kt @@ -59,7 +59,7 @@ class WorldBorderRenderer( shader.native.defines["MAX_DISTANCE"] = MAX_DISTANCE shader.load() - texture = context.textures.staticTextures.createTexture(TEXTURE) + texture = context.textures.staticTextures.create(TEXTURE) context.camera.offset::offset.observe(this) { reload = true } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/DoubleChestRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/DoubleChestRenderer.kt index 1d2c11752..990d88faa 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/DoubleChestRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/DoubleChestRenderer.kt @@ -44,7 +44,7 @@ class DoubleChestRenderer( private fun register(loader: ModelLoader, name: ResourceLocation, texture: ResourceLocation) { val static = loader.context.textures.staticTextures - val override = mapOf(TEXTURE to static.createTexture(texture)) + val override = mapOf(TEXTURE to static.create(texture)) loader.skeletal.register(name, MODEL, override) } @@ -52,8 +52,8 @@ class DoubleChestRenderer( if (textures.size != 2) throw IllegalStateException("Textures must be left and right!") val static = loader.context.textures.staticTextures val override = mapOf( - TEXTURE_5[0] to static.createTexture(textures[0]), - TEXTURE_5[1] to static.createTexture(textures[1]), + TEXTURE_5[0] to static.create(textures[0]), + TEXTURE_5[1] to static.create(textures[1]), ) loader.skeletal.register(name, MODEL_5, override) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/SingleChestRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/SingleChestRenderer.kt index 875c4a7e5..195fa2053 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/SingleChestRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/chest/SingleChestRenderer.kt @@ -41,7 +41,7 @@ class SingleChestRenderer( private val named = minecraft("chest") fun register(loader: ModelLoader, name: ResourceLocation, texture: ResourceLocation) { - val texture = loader.context.textures.staticTextures.createTexture(texture) + val texture = loader.context.textures.staticTextures.create(texture) val model = if (loader.packFormat < 5) MODEL else MODEL_5 loader.skeletal.register(name, model, mapOf(named to texture)) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerBoxRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerBoxRenderer.kt index 48e66c2bd..b0bb76d00 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerBoxRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/shulker/ShulkerBoxRenderer.kt @@ -95,7 +95,7 @@ class ShulkerBoxRenderer( } private fun load(name: ResourceLocation, texture: ResourceLocation, loader: ModelLoader) { - val texture = loader.context.textures.staticTextures.createTexture(texture) + val texture = loader.context.textures.staticTextures.create(texture) loader.skeletal.register(name, TEMPLATE, override = mapOf(this.named to texture)) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapCodeRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapCodeRenderer.kt index e125b00a2..984fe0718 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapCodeRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapCodeRenderer.kt @@ -27,7 +27,8 @@ class BitmapCodeRenderer( ) : AscentedCodePointRenderer { fun updateArray() { - uvStart *= texture.array.uvEnd - uvEnd *= texture.array.uvEnd + val end = texture.array.uvEnd ?: return + uvStart *= end + uvEnd *= end } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapFontType.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapFontType.kt index 7cf7b5ad6..3ab3b1153 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapFontType.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapFontType.kt @@ -78,7 +78,7 @@ class BitmapFontType( private fun load(file: ResourceLocation, height: Int, ascent: Int, chars: List, context: RenderContext): BitmapFontType? { if (chars.isEmpty() || height <= 0) return null - val texture = context.textures.staticTextures.createTexture(file, mipmaps = false, properties = false) + val texture = context.textures.staticTextures.create(file, mipmaps = false, properties = false) texture.load(context) // force load it, we need to calculate the width of every char return load(texture, texture.size.y / chars.size, ascent, chars.codePoints()) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/UnicodeCodeRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/UnicodeCodeRenderer.kt index 2d266d1e9..bf001947b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/UnicodeCodeRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/UnicodeCodeRenderer.kt @@ -19,14 +19,15 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture class UnicodeCodeRenderer( override val texture: Texture, - override var uvStart: Vec2, - override var uvEnd: Vec2, + override val uvStart: Vec2, + override val uvEnd: Vec2, override val width: Float, ) : RasterizedCodePointRenderer { fun updateArray() { - uvStart = uvStart * texture.array.uvEnd - uvEnd = uvEnd * texture.array.uvEnd + val end = texture.array.uvEnd ?: return + uvStart *= end + uvEnd *= end } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeFontType.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeFontType.kt index fbf5276fb..7e058da8b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeFontType.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeFontType.kt @@ -87,7 +87,7 @@ class LegacyUnicodeFontType( sizes.skip(PAGE_SIZE.toLong()) return } - val texture = textures.createTexture(textureFile, mipmaps = false, properties = false) + val texture = textures.create(textureFile, mipmaps = false, properties = false) loadPage(pageId, texture, chars, sizes) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/unihex/UnifontRasterizer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/unihex/UnifontRasterizer.kt index 93252f999..5f75cc4c2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/unihex/UnifontRasterizer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/unihex/UnifontRasterizer.kt @@ -13,11 +13,11 @@ package de.bixilon.minosoft.gui.rendering.font.types.unicode.unihex +import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.gui.rendering.font.renderer.code.CodePointRenderer import de.bixilon.minosoft.gui.rendering.font.types.empty.EmptyCodeRenderer import de.bixilon.minosoft.gui.rendering.font.types.unicode.unihex.UnifontTexture.Companion.isPixelSet import de.bixilon.minosoft.gui.rendering.system.base.texture.array.StaticTextureArray -import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureArray.Companion.TEXTURE_RESOLUTION_ID_MAP class UnifontRasterizer( private val array: StaticTextureArray, @@ -54,15 +54,8 @@ class UnifontRasterizer( } private fun calculateRows(width: Int): Int { - var previous = TEXTURE_RESOLUTION_ID_MAP.last() - for (index in TEXTURE_RESOLUTION_ID_MAP.size - 1 downTo 0) { - val resolution = TEXTURE_RESOLUTION_ID_MAP[index] - val size = resolution * resolution / HEIGHT - if (width >= size) return previous / HEIGHT - previous = resolution - } - - return 1 + val size = array.findResolution(Vec2i(width, HEIGHT)) + return size.y / HEIGHT } private fun createTexture(): UnifontTexture { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/FireOverlay.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/FireOverlay.kt index ab13b42e6..9d5514681 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/FireOverlay.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/FireOverlay.kt @@ -31,7 +31,7 @@ class FireOverlay( private val config = context.connection.profiles.rendering.overlay.fire private val player = context.connection.player private val shader = context.shaders.genericTexture2dShader - private var texture: Texture = context.textures.staticTextures.createTexture("block/fire_1".toResourceLocation().texture()) + private var texture: Texture = context.textures.staticTextures.create("block/fire_1".toResourceLocation().texture()) private val lava = context.connection.registries.fluid[LavaFluid] override val render: Boolean get() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/PowderSnowOverlay.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/PowderSnowOverlay.kt index b8bc56014..34c1e6603 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/PowderSnowOverlay.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/PowderSnowOverlay.kt @@ -23,7 +23,7 @@ import de.bixilon.minosoft.util.KUtil.toResourceLocation class PowderSnowOverlay(context: RenderContext) : SimpleOverlay(context) { private val config = context.connection.profiles.rendering.overlay - override val texture: Texture = context.textures.staticTextures.createTexture(OVERLAY_TEXTURE) + override val texture: Texture = context.textures.staticTextures.create(OVERLAY_TEXTURE) private val strength = FloatAverage(1L * 1000000000L, 0.0f) override var render: Boolean = false get() = config.powderSnow && field diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/PumpkinOverlay.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/PumpkinOverlay.kt index ebe1e0d01..6aad5b132 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/PumpkinOverlay.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/PumpkinOverlay.kt @@ -23,7 +23,7 @@ import de.bixilon.minosoft.util.KUtil.toResourceLocation class PumpkinOverlay(context: RenderContext) : FirstPersonOverlay(context) { private val config = context.connection.profiles.rendering.overlay - override val texture: Texture = context.textures.staticTextures.createTexture(OVERLAY_TEXTURE) + override val texture: Texture = context.textures.staticTextures.create(OVERLAY_TEXTURE) override val render: Boolean get() { if (!config.pumpkin) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WaterOverlay.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WaterOverlay.kt index e6f3e1df7..84cb9eb44 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WaterOverlay.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WaterOverlay.kt @@ -24,7 +24,7 @@ import de.bixilon.minosoft.util.KUtil.toResourceLocation class WaterOverlay(context: RenderContext) : SimpleOverlay(context) { private val player = context.connection.player - override val texture: Texture = context.textures.staticTextures.createTexture("minecraft:misc/underwater".toResourceLocation().texture()) + override val texture: Texture = context.textures.staticTextures.create("minecraft:misc/underwater".toResourceLocation().texture()) override val render: Boolean get() = player.gamemode != Gamemodes.SPECTATOR && player.physics.submersion.eye is WaterFluid diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WorldBorderOverlay.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WorldBorderOverlay.kt index 08f5acd27..98158504a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WorldBorderOverlay.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WorldBorderOverlay.kt @@ -22,7 +22,7 @@ import de.bixilon.minosoft.util.KUtil.toResourceLocation class WorldBorderOverlay(context: RenderContext) : SimpleOverlay(context) { private val config = context.connection.profiles.rendering.overlay - override val texture: Texture = context.textures.staticTextures.createTexture(OVERLAY_TEXTURE) + override val texture: Texture = context.textures.staticTextures.create(OVERLAY_TEXTURE) override val render: Boolean get() = config.worldBorder && context.connection.world.border.isOutside(context.connection.player.physics.position) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/weather/WeatherOverlay.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/weather/WeatherOverlay.kt index 3c2e8fcac..4df77db34 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/weather/WeatherOverlay.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/weather/WeatherOverlay.kt @@ -33,8 +33,8 @@ import java.util.* class WeatherOverlay(private val context: RenderContext) : Overlay { private val world = context.connection.world private val config = context.connection.profiles.rendering.overlay.weather - private val rain = context.textures.staticTextures.createTexture(RAIN) - private val snow = context.textures.staticTextures.createTexture(SNOW) + private val rain = context.textures.staticTextures.create(RAIN) + private val snow = context.textures.staticTextures.create(SNOW) private val precipitation get() = context.connection.player.physics.positionInfo.biome?.precipitation override val render: Boolean get() = world.dimension.effects.weather && world.weather.raining && when (precipitation) { // ToDo: Check if exposed to the sky @@ -70,7 +70,7 @@ class WeatherOverlay(private val context: RenderContext) : Overlay { val offsetMultiplicator = random.nextFloat(0.8f, 1.2f) val alpha = random.nextFloat(0.8f, 1.0f) mesh.addZQuad( - Vec2(offset, 0), OVERLAY_Z, Vec2(offset + step, windowSize.y), Vec2(0.0f), texture.array.uvEnd + Vec2(offset, 0), OVERLAY_Z, Vec2(offset + step, windowSize.y), Vec2(0.0f), texture.array.uvEnd ?: Vec2(1.0f) ) { position, uv -> val transformed = Vec2() transformed.x = position.x / (windowSize.x / 2) - 1.0f diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/BlockModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/BlockModel.kt index 2029c485f..901801146 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/BlockModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/BlockModel.kt @@ -44,14 +44,14 @@ data class BlockModel( fun createTexture(name: String, textures: TextureManager): Texture? { if (!name.startsWith("#")) { - return textures.staticTextures.createTexture(name.toResourceLocation()) + return textures.staticTextures.create(name.toResourceLocation()) } val texture = this.textures?.get(name.substring(1)) if (texture == null || texture !is ResourceLocation) { return null } - return textures.staticTextures.createTexture(texture) + return textures.staticTextures.create(texture) } fun getOrNullTexture(name: String, textures: TextureManager): Texture? { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/fluid/fluids/LavaFluidModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/fluid/fluids/LavaFluidModel.kt index fe0194473..0ed40d5e7 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/fluid/fluids/LavaFluidModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/fluid/fluids/LavaFluidModel.kt @@ -27,8 +27,8 @@ class LavaFluidModel : FluidModel { override val transparency = TextureTransparencies.OPAQUE// TODO: from texture override fun load(context: RenderContext) { - still = context.textures.staticTextures.createTexture(context.models.block.fixTexturePath(STILL).texture()) - flowing = context.textures.staticTextures.createTexture(context.models.block.fixTexturePath(FLOWING).texture()) + still = context.textures.staticTextures.create(context.models.block.fixTexturePath(STILL).texture()) + flowing = context.textures.staticTextures.create(context.models.block.fixTexturePath(FLOWING).texture()) } companion object { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/fluid/fluids/WaterFluidModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/fluid/fluids/WaterFluidModel.kt index d8dc13a62..b0bcd3622 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/fluid/fluids/WaterFluidModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/fluid/fluids/WaterFluidModel.kt @@ -31,8 +31,8 @@ class WaterFluidModel : FluidModel { override val transparency = TextureTransparencies.TRANSLUCENT// TODO: from texture override fun load(context: RenderContext) { - still = context.textures.staticTextures.createTexture(context.models.block.fixTexturePath(STILL).texture()) - flowing = context.textures.staticTextures.createTexture(context.models.block.fixTexturePath(FLOWING).texture()) + still = context.textures.staticTextures.create(context.models.block.fixTexturePath(STILL).texture()) + flowing = context.textures.staticTextures.create(context.models.block.fixTexturePath(FLOWING).texture()) } companion object { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/item/ItemModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/item/ItemModel.kt index fdd4da073..2958c28ea 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/item/ItemModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/item/ItemModel.kt @@ -32,7 +32,7 @@ class ItemModel( if (this.textures == null) return null val texture = this.textures["layer0", "particle"]?.toResourceLocation()?.texture() ?: return null - return ItemModelPrototype(textures.staticTextures.createTexture(texture)) + return ItemModelPrototype(textures.staticTextures.create(texture)) } companion object { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt index ad9cba8f1..649275310 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt @@ -119,7 +119,7 @@ class ParticleRenderer( translucentMesh.load() for (particle in connection.registries.particleType) { for (resourceLocation in particle.textures) { - context.textures.staticTextures.createTexture(resourceLocation) + context.textures.staticTextures.create(resourceLocation) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/SkeletalModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/SkeletalModel.kt index 4b4b85bc1..40c74c36f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/SkeletalModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/SkeletalModel.kt @@ -42,7 +42,7 @@ data class SkeletalModel( if (name in skip) continue val file = name.texture() if (file in skip) continue - val texture = context.textures.staticTextures.createTexture(file) + val texture = context.textures.staticTextures.create(file) this.loadedTextures[name] = SkeletalTextureInstance(properties, texture) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt index a02de0016..7d74834cd 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt @@ -85,7 +85,7 @@ class SkyboxRenderer( override fun init() { for (properties in DefaultDimensionEffects) { val texture = properties.fixedTexture ?: continue - textureCache[texture] = sky.context.textures.staticTextures.createTexture(texture) + textureCache[texture] = sky.context.textures.staticTextures.create(texture) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/planet/MoonRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/planet/MoonRenderer.kt index b661700f4..3280e677e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/planet/MoonRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/planet/MoonRenderer.kt @@ -29,13 +29,14 @@ import java.util.* class MoonRenderer( sky: SkyRenderer, ) : PlanetRenderer(sky) { - override val texture = sky.context.textures.staticTextures.createTexture(MOON_PHASES) + override val texture = sky.context.textures.staticTextures.create(MOON_PHASES) private var phase = MoonPhases.FULL_MOON private fun updateUV(phases: MoonPhases) { val coordinates = PHASE_UV[phases.ordinal] - uvStart = Vec2(1.0f / 4 * coordinates.x, 1.0f / 2 * coordinates.y) * texture.array.uvEnd - uvEnd = Vec2(1.0f / 4 * (coordinates.x + 1), 1.0f / 2 * (coordinates.y + 1)) * texture.array.uvEnd + val end = texture.array.uvEnd ?: Vec2i(1.0f) + uvStart = Vec2(1.0f / 4 * coordinates.x, 1.0f / 2 * coordinates.y) * end + uvEnd = Vec2(1.0f / 4 * (coordinates.x + 1), 1.0f / 2 * (coordinates.y + 1)) * end meshInvalid = true } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/planet/SunRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/planet/SunRenderer.kt index 10940051b..58bb6272b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/planet/SunRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/planet/SunRenderer.kt @@ -27,7 +27,7 @@ import kotlin.math.pow class SunRenderer( sky: SkyRenderer, ) : PlanetRenderer(sky) { - override val texture = sky.context.textures.staticTextures.createTexture(SUN) + override val texture = sky.context.textures.staticTextures.create(SUN) public override fun calculateAngle(): Float { val time = sky.context.connection.world.time diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt index f851e5c9e..d4286439c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt @@ -42,8 +42,8 @@ abstract class TextureManager { if (this::debugTexture.isInitialized) { throw IllegalStateException("Already initialized!") } - debugTexture = staticTextures.createTexture(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION) - whiteTexture = CodeTexturePart(texture = staticTextures.createTexture(minosoft("white").texture(), mipmaps = false), uvStart = Vec2(0.0f, 0.0f), uvEnd = Vec2(0.001f, 0.001f), size = Vec2i(16, 16)) + debugTexture = staticTextures.create(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION) + whiteTexture = CodeTexturePart(texture = staticTextures.create(minosoft("white").texture(), mipmaps = false), uvStart = Vec2(0.0f, 0.0f), uvEnd = Vec2(0.001f, 0.001f), size = Vec2i(16, 16)) } fun initializeSkins(connection: PlayConnection) { 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 0c466cdee..c4dba69e4 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,10 +13,14 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture.array +import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kutil.concurrent.lock.simple.SimpleLock 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.AbstractLatch.Companion.child import de.bixilon.minosoft.assets.util.InputStreamUtil.readAsString import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.gui.rendering.RenderContext @@ -28,6 +32,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.file.PNGTex import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties import de.bixilon.minosoft.util.KUtil.toResourceLocation import de.bixilon.minosoft.util.json.Jackson +import java.util.concurrent.atomic.AtomicInteger abstract class StaticTextureArray( val context: RenderContext, @@ -50,10 +55,9 @@ abstract class StaticTextureArray( return texture } - operator fun plusAssign(texture: Texture) = pushTexture(texture) + operator fun plusAssign(texture: Texture) = push(texture) - - fun pushTexture(texture: Texture) { + fun push(texture: Texture) { lock.lock() other += texture lock.unlock() @@ -62,7 +66,7 @@ abstract class StaticTextureArray( } } - fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean = true, properties: Boolean = true, factory: (mipmaps: Int) -> Texture = { PNGTexture(resourceLocation, mipmaps = it) }): Texture { + open fun create(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 } @@ -92,6 +96,30 @@ abstract class StaticTextureArray( return null } + abstract fun findResolution(size: Vec2i): Vec2i - abstract fun load(latch: AbstractLatch) + + private fun load(latch: AbstractLatch, textures: Collection) { + for (texture in textures) { + if (texture.state != TextureStates.DECLARED) continue + + latch.inc() + DefaultThreadPool += SimplePoolRunnable(ThreadPool.HIGH) { texture.load(context); latch.dec() } + } + } + + protected abstract fun load(animationIndex: AtomicInteger, textures: Collection) + + fun load(latch: AbstractLatch) { + val latch = latch.child(0) + load(latch, named.values) + load(latch, other) + latch.await() + + val animationIndex = AtomicInteger() + load(animationIndex, named.values) + load(animationIndex, other) + + state = TextureArrayStates.LOADED + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/TextureArrayProperties.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/TextureArrayProperties.kt index 2cb0605ae..933fe6aed 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/TextureArrayProperties.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/TextureArrayProperties.kt @@ -16,7 +16,7 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture.array import de.bixilon.kotlinglm.vec2.Vec2 data class TextureArrayProperties( - val uvEnd: Vec2, + val uvEnd: Vec2?, val size: Int, - val pixel: Vec2, + val pixel: Float, ) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/TextureArrayStates.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/TextureArrayStates.kt index 46669c2fc..4ab0362ef 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/TextureArrayStates.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/array/TextureArrayStates.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2021 Moritz Zwerger + * 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. * @@ -15,8 +15,8 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture.array enum class TextureArrayStates { DECLARED, - PRE_LOADED, LOADED, + UPLOADED, UNLOADED, ; } 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 cb0315300..8afe580e4 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 @@ -25,6 +25,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.memory.Memo import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY +@Deprecated("Slow, because of synchronized loading of mcmeta") class SpriteTexture(private val original: Texture) : Texture { override var array: TextureArrayProperties by original::array override var properties: ImageProperties by original::properties 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 caf582fee..83afb751c 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 @@ -14,15 +14,11 @@ package de.bixilon.minosoft.gui.rendering.system.opengl.texture import de.bixilon.kotlinglm.vec2.Vec2 +import de.bixilon.kotlinglm.vec2.Vec2i 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.SimplePoolRunnable import de.bixilon.kutil.latch.AbstractLatch -import de.bixilon.kutil.latch.SimpleLatch 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.TextureArrayProperties import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayStates @@ -46,92 +42,17 @@ class OpenGLTextureArray( async: Boolean, mipmaps: Int, ) : StaticTextureArray(context, async, mipmaps) { - private var textureIds = IntArray(TEXTURE_RESOLUTION_ID_MAP.size) { -1 } + private var handles = IntArray(RESOLUTIONS.size) { -1 } - private val texturesByResolution = Array>(TEXTURE_RESOLUTION_ID_MAP.size) { mutableListOf() } - private val lastTextureId = IntArray(TEXTURE_RESOLUTION_ID_MAP.size) + private val resolution = Array>(RESOLUTIONS.size) { mutableListOf() } + private val lastTextureId = IntArray(RESOLUTIONS.size) init { - context.system.unsafeCast().textureBindingIndex += TEXTURE_RESOLUTION_ID_MAP.size + context.system.unsafeCast().textureBindingIndex += RESOLUTIONS.size } - private fun preLoad(latch: AbstractLatch, textures: Collection) { - for (texture in textures) { - if (texture.state != TextureStates.DECLARED) { - latch.dec() - continue - } - DefaultThreadPool += SimplePoolRunnable(ThreadPool.HIGH) { texture.load(context); latch.dec() } - } - } - - private fun preLoad(animationIndex: AtomicInteger, textures: Collection) { - for (texture in textures) { - check(texture.size.x <= TEXTURE_MAX_RESOLUTION) { "Texture's width exceeds $TEXTURE_MAX_RESOLUTION (${texture.size.x})" } - check(texture.size.y <= TEXTURE_MAX_RESOLUTION) { "Texture's height exceeds $TEXTURE_MAX_RESOLUTION (${texture.size.y})" } - - - var arrayId = -1 - var arrayResolution = -1 - - for (i in TEXTURE_RESOLUTION_ID_MAP.indices) { - arrayResolution = TEXTURE_RESOLUTION_ID_MAP[i] - if (texture.size.x <= arrayResolution && texture.size.y <= arrayResolution) { - arrayId = i - break - } - } - - - val uvEnd: Vec2? = if (texture.size.x == arrayResolution && texture.size.y == arrayResolution) { - null - } else { - Vec2(texture.size) / arrayResolution - } - val singlePixelSize = Vec2(1.0f) / arrayResolution - val array = TextureArrayProperties(uvEnd ?: Vec2(1.0f, 1.0f), arrayResolution, singlePixelSize) - - if (texture is SpriteTexture) { - val animationIndex = animationIndex.getAndIncrement() - val animation = TextureAnimation(texture) - animator.animations += animation - texture.renderData = OpenGLTextureData(-1, -1, uvEnd, animationIndex) - for (split in texture.splitTextures) { - split.renderData = OpenGLTextureData(arrayId, lastTextureId[arrayId]++, uvEnd, animationIndex) - split.array = array - texturesByResolution[arrayId] += split - } - for (frame in texture.properties.animation!!.frames) { - frame.texture = texture.splitTextures[frame.index] - } - } else { - texturesByResolution[arrayId] += texture - texture.renderData = OpenGLTextureData(arrayId, lastTextureId[arrayId]++, uvEnd, -1) - texture.array = array - } - } - } - - @Synchronized - override fun load(latch: AbstractLatch) { - if (state == TextureArrayStates.LOADED || state == TextureArrayStates.PRE_LOADED) { - return - } - val preLoadLatch = SimpleLatch(named.size + other.size) - preLoad(preLoadLatch, named.values) - preLoad(preLoadLatch, other) - preLoadLatch.await() - - val animationIndex = AtomicInteger() - preLoad(animationIndex, named.values) - preLoad(animationIndex, other) - - state = TextureArrayStates.PRE_LOADED - } - - - private fun loadSingleArray(resolution: Int, textures: List): Int { + private fun upload(resolution: Int, textures: List): Int { val textureId = OpenGLTextureUtil.createTextureArray(mipmaps) for (level in 0..mipmaps) { @@ -154,22 +75,20 @@ class OpenGLTextureArray( override fun upload(latch: AbstractLatch?) { - var totalLayers = 0 - for ((index, textures) in texturesByResolution.withIndex()) { - if (textures.isEmpty()) { - continue - } - textureIds[index] = loadSingleArray(TEXTURE_RESOLUTION_ID_MAP[index], textures) - totalLayers += textures.size + var total = 0 + for ((index, textures) in resolution.withIndex()) { + if (textures.isEmpty()) continue + handles[index] = upload(RESOLUTIONS[index], textures) + total += textures.size } - Log.log(LogMessageType.RENDERING, LogLevels.VERBOSE) { "Loaded ${named.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 $total layers!" } animator.init() - state = TextureArrayStates.LOADED + state = TextureArrayStates.UPLOADED } override fun activate() { - for ((index, textureId) in textureIds.withIndex()) { + for ((index, textureId) in handles.withIndex()) { if (textureId == -1) { continue } @@ -182,7 +101,7 @@ class OpenGLTextureArray( shader.use() activate() - for ((index, textureId) in textureIds.withIndex()) { + for ((index, textureId) in handles.withIndex()) { if (textureId == -1) { continue } @@ -192,8 +111,71 @@ class OpenGLTextureArray( } } - companion object { - const val TEXTURE_MAX_RESOLUTION = 2048 - val TEXTURE_RESOLUTION_ID_MAP = intArrayOf(16, 32, 64, 128, 256, 512, 1024, TEXTURE_MAX_RESOLUTION) // A 12x12 texture will be saved in texture id 0 (in 0 are only 16x16 textures). Animated textures get split + override fun findResolution(size: Vec2i): Vec2i { + if (size.x >= MAX_RESOLUTION || size.y >= MAX_RESOLUTION) return Vec2i(MAX_RESOLUTION) + val array = findArray(size) + if (array < 0) return Vec2i(0, 0) + return Vec2i(RESOLUTIONS[array]) + } + + private fun findArray(size: Vec2i): Int { + for ((index, resolution) in RESOLUTIONS.withIndex()) { + if (size.x > resolution || size.y > resolution) continue + return index + } + + return -1 + } + + private fun load(animationIndex: AtomicInteger, arrayId: Int, texture: Texture) { + val resolution = RESOLUTIONS[arrayId] + val pixel = PIXEL[arrayId] + val size = texture.size + + val uvEnd = if (size.x == resolution && size.y == resolution) null else Vec2(size) / resolution + val array = TextureArrayProperties(uvEnd, resolution, pixel) + + if (texture !is SpriteTexture) { + this.resolution[arrayId] += texture + texture.renderData = OpenGLTextureData(arrayId, lastTextureId[arrayId]++, uvEnd, -1) + texture.array = array + return + } + + val animationIndex = animationIndex.getAndIncrement() + val animation = TextureAnimation(texture) + animator.animations += animation + + texture.renderData = OpenGLTextureData(-1, -1, uvEnd, animationIndex) + for (split in texture.splitTextures) { + split.renderData = OpenGLTextureData(arrayId, lastTextureId[arrayId]++, uvEnd, animationIndex) + split.array = array + this.resolution[arrayId] += split + } + for (frame in texture.properties.animation!!.frames) { + frame.texture = texture.splitTextures[frame.index] + } + } + + override fun load(animationIndex: AtomicInteger, textures: Collection) { + for (texture in textures) { + if (texture.size.x > MAX_RESOLUTION || texture.size.y > MAX_RESOLUTION) { + Log.log(LogMessageType.LOADING, LogLevels.WARN) { "Texture $texture exceeds max resolution ($MAX_RESOLUTION): ${texture.size}" } + continue + } + + val arrayId = findArray(texture.size) + if (arrayId == -1) { + Log.log(LogMessageType.LOADING, LogLevels.WARN) { "Can not find texture array for $arrayId" } + continue + } + load(animationIndex, arrayId, texture) + } + } + + private companion object { + const val MAX_RESOLUTION = 2048 + val RESOLUTIONS = intArrayOf(16, 32, 64, 128, 256, 512, 1024, MAX_RESOLUTION) // A 12x12 texture will be saved in texture id 0 (in 0 are only 16x16 textures). Animated textures get split + val PIXEL = FloatArray(RESOLUTIONS.size) { 1.0f / RESOLUTIONS[it] } } }