diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt index 83a9c049c..09669d840 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -38,9 +38,7 @@ import de.bixilon.minosoft.gui.rendering.stats.ExperimentalRenderStats import de.bixilon.minosoft.gui.rendering.stats.RenderStats import de.bixilon.minosoft.gui.rendering.system.base.IntegratedBufferTypes import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem -import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem import de.bixilon.minosoft.gui.rendering.system.window.BaseWindow -import de.bixilon.minosoft.gui.rendering.system.window.GLFWWindow import de.bixilon.minosoft.gui.rendering.tint.TintManager import de.bixilon.minosoft.gui.rendering.util.ScreenshotTaker import de.bixilon.minosoft.gui.rendering.world.LightMap @@ -60,8 +58,8 @@ class RenderWindow( private val profile = connection.profiles.rendering val preferQuads = profile.advanced.preferQuads - val window: BaseWindow = GLFWWindow(this, connection) - val renderSystem: RenderSystem = OpenGLRenderSystem(this) + val window = BaseWindow.createWindow(this) + val renderSystem = RenderSystem.createRenderSystem(this) val camera = Camera(this) val inputHandler = RenderWindowInputHandler(this) @@ -151,7 +149,7 @@ class RenderWindow( // Init stage val initLatch = CountUpAndDownLatch(1, latch) Log.log(LogMessageType.RENDERING_LOADING, LogLevels.VERBOSE) { "Generating font and gathering textures (${stopwatch.labTime()})..." } - textureManager.loadDefaultTextures() + textureManager.loadDefaultTextures(connection.assetsManager) font = FontLoader.load(this, initLatch) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/WorldGUIConsumer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/WorldGUIConsumer.kt index 1425a3cad..83cbf59ec 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/WorldGUIConsumer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/WorldGUIConsumer.kt @@ -21,6 +21,7 @@ import de.bixilon.minosoft.gui.rendering.font.renderer.ChatComponentRenderer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMeshCache import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions +import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh @@ -28,9 +29,9 @@ import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh class WorldGUIConsumer(val mesh: SingleWorldMesh, val transform: Mat4, val light: Int) : GUIVertexConsumer { override val order: Array> get() = mesh.order - override fun addVertex(position: Vec2t<*>, texture: AbstractTexture, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { + override fun addVertex(position: Vec2t<*>, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { val transformed = transform.fastTimes(position.x.toFloat() / ChatComponentRenderer.TEXT_BLOCK_RESOLUTION, -position.y.toFloat() / ChatComponentRenderer.TEXT_BLOCK_RESOLUTION) - mesh.addVertex(transformed, uv, texture, tint.rgb, light) + mesh.addVertex(transformed, uv, texture as AbstractTexture, tint.rgb, light) } override fun addCache(cache: GUIMeshCache) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/DynamicImageElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/DynamicImageElement.kt new file mode 100644 index 000000000..512bc44ae --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/DynamicImageElement.kt @@ -0,0 +1,82 @@ +/* + * Minosoft + * Copyright (C) 2020-2022 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.gui.elements.primitive + +import de.bixilon.kotlinglm.vec2.Vec2 +import de.bixilon.kotlinglm.vec2.Vec2i +import de.bixilon.minosoft.data.text.ChatColors +import de.bixilon.minosoft.data.text.RGBColor +import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer +import de.bixilon.minosoft.gui.rendering.gui.elements.Element +import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh +import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer +import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions +import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture +import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY +import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY + +open class DynamicImageElement( + guiRenderer: GUIRenderer, + texture: DynamicTexture?, + uvStart: Vec2 = Vec2.EMPTY, + uvEnd: Vec2 = Vec2(1.0f, 1.0f), + size: Vec2i = Vec2i.EMPTY, + tint: RGBColor = ChatColors.WHITE, +) : Element(guiRenderer, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6) { + var texture: DynamicTexture? = texture + set(value) { + field = value + cacheUpToDate = false + } + var uvStart: Vec2 = uvStart + set(value) { + field = value + cacheUpToDate = false + } + var uvEnd: Vec2 = uvEnd + set(value) { + field = value + cacheUpToDate = false + } + + override var size: Vec2i + get() = super.size + set(value) { + super.size = value + cacheUpToDate = false + } + + override var prefSize: Vec2i + get() = size + set(value) { + size = value + } + + var tint: RGBColor = tint + set(value) { + field = value + cacheUpToDate = false + } + + init { + this.size = size + } + + override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) { + consumer.addQuad(offset, offset + size, texture ?: return, uvStart, uvEnd, tint, options) + } + + override fun forceSilentApply() = Unit + override fun silentApply(): Boolean = false +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListEntryElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListEntryElement.kt index db3ddbd02..66c233b68 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListEntryElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/tab/TabListEntryElement.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab +import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.data.abilities.Gamemodes import de.bixilon.minosoft.data.player.tab.TabListItem @@ -25,6 +26,7 @@ import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Compa import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ColorElement +import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.DynamicImageElement import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions @@ -38,6 +40,7 @@ class TabListEntryElement( val item: TabListItem, width: Int, ) : Element(guiRenderer), Pollable, Comparable { + init { _parent = tabList } @@ -45,6 +48,7 @@ class TabListEntryElement( // ToDo: Skin private val background: ColorElement + private val skinElement = DynamicImageElement(guiRenderer, guiRenderer.renderWindow.textureManager.alexTexture, uvStart = Vec2(0.125), uvEnd = Vec2(0.25), size = Vec2i(8, 8)) private val nameElement = TextElement(guiRenderer, "", background = false, parent = this) private lateinit var pingElement: AtlasImageElement @@ -77,8 +81,10 @@ class TabListEntryElement( } override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) { + skinElement background.render(offset, consumer, options) - nameElement.render(offset, consumer, options) + skinElement.render(offset, consumer, options) + nameElement.render(offset + Vec2i(skinElement.size.x + PADDING, PADDING), consumer, options) pingElement.render(offset + Vec2i(HorizontalAlignments.RIGHT.getOffset(maxSize.x, pingElement.size.x + PADDING), PADDING), consumer, options) } @@ -96,7 +102,7 @@ class TabListEntryElement( nameElement.text = displayName - this.prefSize = Vec2i((PADDING * 2) + nameElement.prefSize.x + INNER_MARGIN + pingElement.prefSize.x, HEIGHT) + this.prefSize = Vec2i((PADDING * 3) + skinElement.prefSize.x + nameElement.prefSize.x + INNER_MARGIN + pingElement.prefSize.x, HEIGHT) background.size = size cacheUpToDate = false } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMesh.kt index f32819717..f2c1f1ef3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMesh.kt @@ -18,7 +18,7 @@ import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2t import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.gui.rendering.RenderWindow -import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.orthoTimes @@ -31,7 +31,7 @@ class GUIMesh( data: DirectArrayFloatList, ) : Mesh(renderWindow, GUIMeshStruct, initialCacheSize = 40000, clearOnLoad = false, data = data), GUIVertexConsumer { - override fun addVertex(position: Vec2t<*>, texture: AbstractTexture, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { + override fun addVertex(position: Vec2t<*>, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { addVertex(data, matrix, position, texture, uv, tint, options) } @@ -50,7 +50,7 @@ class GUIMesh( companion object { - fun addVertex(data: AbstractFloatList, matrix: Mat4, position: Vec2t<*>, texture: AbstractTexture, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { + fun addVertex(data: AbstractFloatList, matrix: Mat4, position: Vec2t<*>, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { val outPosition = matrix orthoTimes position var color = tint.rgba @@ -69,7 +69,7 @@ class GUIMesh( data.add(outPosition.y) data.add(uv.x) data.add(uv.y) - data.add(Float.fromBits(texture.renderData.shaderTextureId)) + data.add(Float.fromBits(texture.shaderId)) data.add(Float.fromBits(color)) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMeshCache.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMeshCache.kt index b89c12779..b1360aa78 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMeshCache.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMeshCache.kt @@ -18,7 +18,7 @@ import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kotlinglm.vec2.Vec2t import de.bixilon.minosoft.data.text.RGBColor -import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY import de.bixilon.minosoft.util.collections.floats.AbstractFloatList import de.bixilon.minosoft.util.collections.floats.HeapArrayFloatList @@ -41,7 +41,7 @@ class GUIMeshCache( } } - override fun addVertex(position: Vec2t<*>, texture: AbstractTexture, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { + override fun addVertex(position: Vec2t<*>, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { GUIMesh.addVertex(data, matrix, position, texture, uv, tint, options) revision++ } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIVertexConsumer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIVertexConsumer.kt index 9ff1fedc3..85ed8ef26 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIVertexConsumer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIVertexConsumer.kt @@ -17,14 +17,14 @@ import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2t import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.gui.rendering.gui.atlas.TextureLike -import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable interface GUIVertexConsumer { val order: Array> - fun addVertex(position: Vec2t<*>, texture: AbstractTexture, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) + fun addVertex(position: Vec2t<*>, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) - fun addQuad(start: Vec2t<*>, end: Vec2t<*>, texture: AbstractTexture, uvStart: Vec2 = Vec2(0.0f, 0.0f), uvEnd: Vec2 = Vec2(1.0f, 1.0f), tint: RGBColor, options: GUIVertexOptions?) { + fun addQuad(start: Vec2t<*>, end: Vec2t<*>, texture: ShaderIdentifiable, uvStart: Vec2 = Vec2(0.0f, 0.0f), uvEnd: Vec2 = Vec2(1.0f, 1.0f), tint: RGBColor, options: GUIVertexOptions?) { val positions = arrayOf( start, Vec2(end.x, start.y), diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderSystem.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderSystem.kt index fba9fd925..2dd2846b9 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderSystem.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderSystem.kt @@ -17,6 +17,7 @@ import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.data.text.Colors import de.bixilon.minosoft.data.text.RGBColor +import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.system.base.buffer.frame.Framebuffer import de.bixilon.minosoft.gui.rendering.system.base.buffer.uniform.FloatUniformBuffer import de.bixilon.minosoft.gui.rendering.system.base.buffer.uniform.IntUniformBuffer @@ -24,6 +25,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.FloatVertexBu import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.PrimitiveTypes import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager +import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct import de.bixilon.minosoft.util.KUtil.toResourceLocation import java.nio.ByteBuffer @@ -118,4 +120,12 @@ interface RenderSystem { fun polygonOffset(factor: Float, unit: Float) + + + companion object { + + fun createRenderSystem(renderWindow: RenderWindow): RenderSystem { + return OpenGLRenderSystem(renderWindow) + } + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/ShaderIdentifiable.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/ShaderIdentifiable.kt new file mode 100644 index 000000000..dc3213d9f --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/ShaderIdentifiable.kt @@ -0,0 +1,18 @@ +/* + * Minosoft + * Copyright (C) 2020-2022 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.base.texture + +interface ShaderIdentifiable { + val shaderId: Int +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/StaticTextureArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/StaticTextureArray.kt index 5aaa3af27..dcea8715a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/StaticTextureArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/StaticTextureArray.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2021 Moritz Zwerger + * Copyright (C) 2020-2022 Moritz Zwerger * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * @@ -13,13 +13,21 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture +import de.bixilon.kutil.latch.CountUpAndDownLatch import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.PNGTexture interface StaticTextureArray : TextureArray { val textures: MutableMap + val animator: SpriteAnimator + val state: TextureArrayStates - override fun get(resourceLocation: ResourceLocation): AbstractTexture? { + fun get(resourceLocation: ResourceLocation): AbstractTexture? { return textures[resourceLocation] } + + fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean = true, default: () -> AbstractTexture = { PNGTexture(resourceLocation, generateMipMaps = mipmaps) }): AbstractTexture + + fun preLoad(latch: CountUpAndDownLatch) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureArray.kt index ede016ed7..44fd3f561 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureArray.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2021 Moritz Zwerger + * Copyright (C) 2020-2022 Moritz Zwerger * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * @@ -14,21 +14,10 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture import de.bixilon.kutil.latch.CountUpAndDownLatch -import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader -import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture -import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.PNGTexture interface TextureArray { - val animator: SpriteAnimator - val state: TextureArrayStates - - operator fun get(resourceLocation: ResourceLocation): AbstractTexture? - fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean = true, default: () -> AbstractTexture = { PNGTexture(resourceLocation, generateMipMaps = mipmaps) }): AbstractTexture - - fun preLoad(latch: CountUpAndDownLatch) - fun load(latch: CountUpAndDownLatch) - fun use(shader: Shader, arrayName: String = "uTextures") + fun use(shader: Shader, name: String = "uTextures") } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt index 495f91d7b..73a1b724c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt @@ -15,24 +15,44 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i +import de.bixilon.kutil.uuid.UUIDUtil.toUUID +import de.bixilon.minosoft.assets.AssetsManager import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.gui.atlas.TextureLikeTexture +import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture +import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureArray import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil.readTexture +import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture +import de.bixilon.minosoft.util.KUtil.toResourceLocation abstract class TextureManager { - abstract var staticTextures: StaticTextureArray + abstract val staticTextures: StaticTextureArray + abstract val dynamicTextures: DynamicTextureArray lateinit var debugTexture: AbstractTexture private set lateinit var whiteTexture: TextureLikeTexture private set + lateinit var steveTexture: DynamicTexture + private set + lateinit var alexTexture: DynamicTexture + private set - fun loadDefaultTextures() { + fun loadDefaultTextures(assetsManager: AssetsManager) { if (this::debugTexture.isInitialized) { throw IllegalStateException("Already initialized!") } debugTexture = staticTextures.createTexture(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION) whiteTexture = TextureLikeTexture(texture = staticTextures.createTexture(ResourceLocation("minosoft:textures/white.png")), uvStart = Vec2(0.0f, 0.0f), uvEnd = Vec2(0.001f, 0.001f), size = Vec2i(16, 16)) + + loadDefaultSkins(assetsManager) + } + + private fun loadDefaultSkins(assetsManager: AssetsManager) { + // ToDo: For testing purposes only, they will be moved to static textures + steveTexture = dynamicTextures.push("3780a46b-a725-4b22-8366-01056c698386".toUUID()) { assetsManager["minecraft:entity/steve".toResourceLocation().texture()].readTexture().second } + alexTexture = dynamicTextures.push("3780a46b-a725-4b22-8366-01056c698386".toUUID()) { assetsManager["minecraft:entity/alex".toResourceLocation().texture()].readTexture().second } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTexture.kt new file mode 100644 index 000000000..44b673b12 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTexture.kt @@ -0,0 +1,23 @@ +/* + * Minosoft + * Copyright (C) 2020-2022 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic + +import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable +import java.util.* +import java.util.concurrent.atomic.AtomicInteger + +interface DynamicTexture : ShaderIdentifiable { + val uuid: UUID + val usages: AtomicInteger +} 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 new file mode 100644 index 000000000..608d10d96 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/dynamic/DynamicTextureArray.kt @@ -0,0 +1,26 @@ +/* + * Minosoft + * Copyright (C) 2020-2022 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic + +import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureArray +import java.nio.ByteBuffer +import java.util.* + +interface DynamicTextureArray : TextureArray { + val size: Int + + fun push(identifier: UUID, data: () -> ByteBuffer): DynamicTexture + fun remove(texture: DynamicTexture) + fun remove(uuid: UUID) +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/AbstractTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/AbstractTexture.kt index 5df4a167e..32f28251c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/AbstractTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/AbstractTexture.kt @@ -17,15 +17,14 @@ import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.assets.AssetsManager import de.bixilon.minosoft.data.registries.ResourceLocation +import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable 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.opengl.texture.OpenGLTextureArray +import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties -import example.jonathan2520.SRGBAverager -import org.lwjgl.BufferUtils import java.nio.ByteBuffer -interface AbstractTexture { +interface AbstractTexture : ShaderIdentifiable { val resourceLocation: ResourceLocation var textureArrayUV: Vec2 @@ -45,61 +44,15 @@ interface AbstractTexture { fun load(assetsManager: AssetsManager) + override val shaderId: Int + get() = renderData.shaderTextureId + fun generateMipMaps(data: ByteBuffer = this.data!!): Array { - val images: MutableList = mutableListOf() - - images += data if (!generateMipMaps) { - return images.toTypedArray() + return arrayOf(data) } - var currentData = data - for (i in 1 until OpenGLTextureArray.MAX_MIPMAP_LEVELS) { - val mipMapSize = Vec2i(size.x shr i, size.y shr i) - if (mipMapSize.x <= 0 || mipMapSize.y <= 0) { - break - } - currentData = generateMipmap(currentData, Vec2i(size.x shr (i - 1), size.y shr (i - 1))) - images += currentData - } - - 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) - } - } - - buffer.rewind() - return buffer + return OpenGLTextureUtil.generateMipMaps(data, size) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/MemoryTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/MemoryTexture.kt index 1e884cf6e..cc3086f8f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/MemoryTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/MemoryTexture.kt @@ -43,6 +43,7 @@ class MemoryTexture( init { val data = BufferUtils.createByteBuffer(size.x * size.y * PNGDecoder.Format.RGBA.numComponents) + this.data = data generator?.let { var index = 0 diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/PNGTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/PNGTexture.kt index 11e56d08e..a5fa8e5ba 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/PNGTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/texture/PNGTexture.kt @@ -19,14 +19,9 @@ import de.bixilon.minosoft.assets.AssetsManager import de.bixilon.minosoft.data.registries.ResourceLocation 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.opengl.texture.OpenGLTextureUtil.readTexture import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties -import de.matthiasmann.twl.utils.PNGDecoder -import org.lwjgl.BufferUtils -import java.awt.image.BufferedImage -import java.io.ByteArrayOutputStream -import java.io.DataOutputStream import java.nio.ByteBuffer -import javax.imageio.ImageIO class PNGTexture( @@ -57,26 +52,9 @@ class PNGTexture( return } - val decoder = PNGDecoder(assetsManager[resourceLocation]) - val data = BufferUtils.createByteBuffer(decoder.width * decoder.height * PNGDecoder.Format.RGBA.numComponents) - try { - decoder.decode(data, decoder.width * PNGDecoder.Format.RGBA.numComponents, PNGDecoder.Format.RGBA) - } catch (exception: Throwable) { - // ToDo: This somehow crashes with some resource packs - // exception.printStackTrace() - val image: BufferedImage = ImageIO.read(assetsManager[resourceLocation]) - val rgb = image.getRGB(0, 0, image.width, image.height, null, 0, image.width) + val (size, data) = assetsManager[resourceLocation].readTexture() - val byteOutput = ByteArrayOutputStream() - val dataOutput = DataOutputStream(byteOutput) - for (color in rgb) { - dataOutput.writeInt(color shl 8) - } - - data.put(byteOutput.toByteArray()) - } - - size = Vec2i(decoder.width, decoder.height) + this.size = size transparency = TextureTransparencies.OPAQUE for (i in 0 until data.limit() / 4) { val alpha = data[i * 4 + 3].toInt() and 0xFF 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 17291ca0d..2e3d043c4 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 @@ -151,16 +151,9 @@ class OpenGLTextureArray( @Synchronized private fun loadSingleArray(resolution: Int, textures: List): 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_MAG_FILTER, GL_NEAREST) - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, MAX_MIPMAP_LEVELS - 1) + val textureId = OpenGLTextureUtil.createTextureArray() - for (level in 0 until MAX_MIPMAP_LEVELS) { + for (level in 0 until OpenGLTextureUtil.MAX_MIPMAP_LEVELS) { 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?) } @@ -199,7 +192,7 @@ class OpenGLTextureArray( } - override fun use(shader: Shader, arrayName: String) { + override fun use(shader: Shader, name: String) { shader.use() for ((index, textureId) in textureIds.withIndex()) { @@ -208,7 +201,7 @@ class OpenGLTextureArray( } glActiveTexture(GL_TEXTURE0 + index) glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) - shader.setTexture("$arrayName[$index]", index) + shader.setTexture("$name[$index]", index) } } @@ -216,6 +209,5 @@ class OpenGLTextureArray( companion object { const val TEXTURE_MAX_RESOLUTION = 1024 val TEXTURE_RESOLUTION_ID_MAP = intArrayOf(16, 32, 64, 128, 256, 512, TEXTURE_MAX_RESOLUTION) // A 12x12 texture will be saved in texture id 0 (in 0 are only 16x16 textures). Animated textures get split - const val MAX_MIPMAP_LEVELS = 5 } } 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 bae460296..2efdea56c 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 @@ -16,7 +16,10 @@ package de.bixilon.minosoft.gui.rendering.system.opengl.texture import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.system.base.texture.StaticTextureArray import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager +import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureArray +import de.bixilon.minosoft.gui.rendering.system.opengl.texture.dynamic.OpenGLDynamicTextureArray class OpenGLTextureManager(val renderWindow: RenderWindow) : TextureManager() { - override var staticTextures: StaticTextureArray = OpenGLTextureArray(renderWindow) + override val staticTextures: StaticTextureArray = OpenGLTextureArray(renderWindow) + override val dynamicTextures: DynamicTextureArray = OpenGLDynamicTextureArray(renderWindow, resolution = 64) } 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 new file mode 100644 index 000000000..42d64fa03 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureUtil.kt @@ -0,0 +1,127 @@ +/* + * Minosoft + * Copyright (C) 2020-2022 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.opengl.texture + +import de.bixilon.kotlinglm.vec2.Vec2i +import de.matthiasmann.twl.utils.PNGDecoder +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.awt.image.BufferedImage +import java.io.ByteArrayOutputStream +import java.io.DataOutputStream +import java.io.InputStream +import java.nio.ByteBuffer +import javax.imageio.ImageIO + +object OpenGLTextureUtil { + const val MAX_MIPMAP_LEVELS = 5 + + + fun createTextureArray(): 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_MAG_FILTER, GL_NEAREST) + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, MAX_MIPMAP_LEVELS - 1) + + return textureId + } + + fun generateMipMaps(data: ByteBuffer, size: Vec2i): Array { + val images: MutableList = mutableListOf() + + images += data + + var currentData = data + for (i in 1 until MAX_MIPMAP_LEVELS) { + val mipMapSize = Vec2i(size.x shr i, size.y shr i) + if (mipMapSize.x <= 0 || mipMapSize.y <= 0) { + break + } + currentData = generateMipmap(currentData, Vec2i(size.x shr (i - 1), size.y shr (i - 1))) + images += currentData + } + + 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) + } + } + + buffer.rewind() + return buffer + } + + private fun InputStream.readFallbackTexture(): Pair { + // ToDo: This somehow crashes with some resource packs + val image: BufferedImage = ImageIO.read(this) + val rgb = image.getRGB(0, 0, image.width, image.height, null, 0, image.width) + + val byteOutput = ByteArrayOutputStream() + val dataOutput = DataOutputStream(byteOutput) + for (color in rgb) { + dataOutput.writeInt(color shl 8) + } + + return Pair(Vec2i(image.width, image.height), ByteBuffer.wrap(byteOutput.toByteArray())) + } + + fun InputStream.readTexture(): Pair { + return try { + val decoder = PNGDecoder(this) + val data = BufferUtils.createByteBuffer(decoder.width * decoder.height * PNGDecoder.Format.RGBA.numComponents) + decoder.decode(data, decoder.width * PNGDecoder.Format.RGBA.numComponents, PNGDecoder.Format.RGBA) + + Pair(Vec2i(decoder.width, decoder.height), data) + } catch (exception: Throwable) { + readFallbackTexture() + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTexture.kt new file mode 100644 index 000000000..54961c6cc --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTexture.kt @@ -0,0 +1,25 @@ +/* + * Minosoft + * Copyright (C) 2020-2022 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.opengl.texture.dynamic + +import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture +import java.util.* +import java.util.concurrent.atomic.AtomicInteger + +class OpenGLDynamicTexture( + override val uuid: UUID, + override val shaderId: Int, +) : DynamicTexture { + override val usages = AtomicInteger() +} 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 new file mode 100644 index 000000000..196eef124 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/dynamic/OpenGLDynamicTextureArray.kt @@ -0,0 +1,99 @@ +/* + * Minosoft + * Copyright (C) 2020-2022 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.opengl.texture.dynamic + +import de.bixilon.kotlinglm.vec2.Vec2i +import de.bixilon.kutil.latch.CountUpAndDownLatch +import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader +import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture +import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureArray +import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil +import org.lwjgl.opengl.GL11.* +import org.lwjgl.opengl.GL12 +import org.lwjgl.opengl.GL12.glTexImage3D +import org.lwjgl.opengl.GL12.glTexSubImage3D +import org.lwjgl.opengl.GL13.GL_TEXTURE0 +import org.lwjgl.opengl.GL13.glActiveTexture +import org.lwjgl.opengl.GL30.GL_TEXTURE_2D_ARRAY +import java.nio.ByteBuffer +import java.util.* + +class OpenGLDynamicTextureArray( + val renderWindow: RenderWindow, + val index: Int = 6, + val resolution: Int, +) : DynamicTextureArray { + private val textures: Array = arrayOfNulls(32) + private var textureId = -1 + + override val size: Int + get() = 2 + + override fun remove(uuid: UUID) { + TODO("Not yet implemented") + } + + override fun remove(texture: DynamicTexture) { + TODO("Not yet implemented") + } + + override fun push(identifier: UUID, data: () -> ByteBuffer): OpenGLDynamicTexture { + val bytes = data() + + check(bytes.limit() == resolution * resolution * 4) { "Texture must have a size of ${resolution}x${resolution}" } + + val mipmaps = OpenGLTextureUtil.generateMipMaps(bytes, Vec2i(resolution, resolution)) + + glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) + for ((level, mipmap) in mipmaps.withIndex()) { + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, level, resolution, resolution, 1, GL_RGBA, GL_UNSIGNED_BYTE, mipmap) + } + + return OpenGLDynamicTexture(identifier, createShaderIdentifier(index = 0)) + } + + private fun createShaderIdentifier(array: Int = this.index, index: Int): Int { + return (array shl 28) or (index shl 12) or 0 + } + + + override fun load(latch: CountUpAndDownLatch) { + val textureId = OpenGLTextureUtil.createTextureArray() + this.textureId = textureId + + + for (level in 0 until OpenGLTextureUtil.MAX_MIPMAP_LEVELS) { + glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL12.GL_RGBA, resolution shr level, resolution shr level, textures.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?) + } + + + for (i in textures.indices) { + for (level in 0 until OpenGLTextureUtil.MAX_MIPMAP_LEVELS) { + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, i, resolution, resolution, 1, GL_RGBA, GL_UNSIGNED_BYTE, ByteBuffer.wrap(ByteArray(resolution * resolution * 4))) + } + } + + + this.textureId = textureId + } + + override fun use(shader: Shader, name: String) { + shader.use() + + glActiveTexture(GL_TEXTURE0 + index) + glBindTexture(GL_TEXTURE_2D_ARRAY, textureId) + shader.setTexture("$name[$index]", index) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/BaseWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/BaseWindow.kt index 463304c80..e0c6ca34d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/BaseWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/BaseWindow.kt @@ -18,6 +18,7 @@ import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.assets.AssetsManager import de.bixilon.minosoft.config.profile.delegate.watcher.SimpleProfileDelegateWatcher.Companion.profileWatchRendering import de.bixilon.minosoft.config.profile.profiles.rendering.RenderingProfile +import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.terminal.RunConfiguration import de.bixilon.minosoft.util.KUtil.toResourceLocation import de.matthiasmann.twl.utils.PNGDecoder @@ -92,5 +93,10 @@ interface BaseWindow { get() = Vec2i(300, 100) val DEFAULT_MAXIMUM_WINDOW_SIZE: Vec2i get() = Vec2i(-1, -1) + + + fun createWindow(renderWindow: RenderWindow): BaseWindow { + return GLFWWindow(renderWindow) + } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/GLFWWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/GLFWWindow.kt index 8ed7bd957..2e751f6cf 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/GLFWWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/GLFWWindow.kt @@ -45,7 +45,7 @@ import java.nio.ByteBuffer class GLFWWindow( private val renderWindow: RenderWindow, - private val eventMaster: AbstractEventMaster, + private val eventMaster: AbstractEventMaster = renderWindow.connection, ) : BaseWindow { private var mousePosition = Vec2d.EMPTY private var skipNextMouseEvent = true diff --git a/src/main/resources/assets/minosoft/rendering/shader/includes/texture.glsl b/src/main/resources/assets/minosoft/rendering/shader/includes/texture.glsl index 6e6be355d..a32ae8c9b 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/includes/texture.glsl +++ b/src/main/resources/assets/minosoft/rendering/shader/includes/texture.glsl @@ -12,9 +12,11 @@ */ -uniform sampler2DArray uTextures[7]; +uniform sampler2DArray uTextures[8]; -vec4 getTexture(uint textureId, vec3 uv) { // ToDo: This method is just stupid and workarounds an opengl crash with mesa drivers +// ToDo: Those methods are just stupid and workaround an opengl crash with mesa drivers + +vec4 getTexture(uint textureId, vec3 uv) { #if defined __NVIDIA || defined __AMD return texture(uTextures[textureId], uv); #else @@ -25,12 +27,13 @@ vec4 getTexture(uint textureId, vec3 uv) { // ToDo: This method is just stupid a case 4u: return texture(uTextures[4], uv); case 5u: return texture(uTextures[5], uv); case 6u: return texture(uTextures[6], uv); + case 7u: return texture(uTextures[7], uv); } return texture(uTextures[0], uv); #endif } -vec4 getTexture(uint textureId, vec3 uv, float mipmapLevel) { // ToDo: This method is just stupid and workarounds an opengl crash with mesa drivers +vec4 getTexture(uint textureId, vec3 uv, float mipmapLevel) { #if defined __NVIDIA || defined __AMD return textureLod(uTextures[textureId], uv, mipmapLevel); #else @@ -41,6 +44,7 @@ vec4 getTexture(uint textureId, vec3 uv, float mipmapLevel) { // ToDo: This meth case 4u: return textureLod(uTextures[4], uv, mipmapLevel); case 5u: return textureLod(uTextures[5], uv, mipmapLevel); case 6u: return textureLod(uTextures[6], uv, mipmapLevel); + case 7u: return textureLod(uTextures[7], uv, mipmapLevel); } return textureLod(uTextures[0], uv, mipmapLevel); #endif