mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-09 07:20:04 -04:00
wip mixed TextureFormats
This is the first step for "compressing" texture data from RGBA8 to RGBA2. That should theoretically reduce font vram usage to 1/4 (~100MB -> ~25MB). Needs to be tested and actually used.
This commit is contained in:
parent
d818661289
commit
03ffa29074
@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.font.types.bitmap
|
||||
import de.bixilon.kotlinglm.vec2.Vec2
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.empty.EmptyCodeRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.data.TextureData
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture
|
||||
import de.bixilon.minosoft.gui.rendering.system.dummy.texture.DummyTexture
|
||||
@ -35,7 +36,7 @@ class BitmapFontTypeTest {
|
||||
val rows = (start.size / 16) + if (start.size % 16 == 0) 0 else 1
|
||||
val size = Vec2i(width * 16, rows * height)
|
||||
|
||||
val buffer = ByteBuffer.allocate(size.x * size.y * 4)
|
||||
val buffer = ByteBuffer.allocate(size.x * size.y)
|
||||
|
||||
for (row in 0 until rows) {
|
||||
for (height in 0 until height) {
|
||||
@ -44,10 +45,6 @@ class BitmapFontTypeTest {
|
||||
val end = end.getOrNull((row * 16) + char) ?: width
|
||||
|
||||
for (pixel in 0 until width) {
|
||||
buffer.put(0xFF.toByte())
|
||||
buffer.put(0xFF.toByte())
|
||||
buffer.put(0xFF.toByte())
|
||||
|
||||
if (pixel in start..end) {
|
||||
buffer.put(0xFF.toByte())
|
||||
} else {
|
||||
@ -61,7 +58,7 @@ class BitmapFontTypeTest {
|
||||
|
||||
val texture = DummyTexture()
|
||||
texture.size = size
|
||||
texture.data = TextureData(size, buffer)
|
||||
texture.data = TextureData(size, TextureFormats.RGBA2, buffer)
|
||||
|
||||
return texture
|
||||
}
|
||||
|
@ -78,9 +78,7 @@ class UnihexFontTypeTest {
|
||||
}
|
||||
|
||||
private fun ByteArray.assertPixel(index: Int, set: Boolean = true) {
|
||||
val offset = index * 4
|
||||
|
||||
val value = this[offset + 0].toInt() or this[offset + 1].toInt() or this[offset + 2].toInt() or this[offset + 3].toInt()
|
||||
val value = this[index + 0].toInt()
|
||||
|
||||
if (set) {
|
||||
assertTrue(value != 0, "Did expect pixel at $index")
|
||||
|
@ -17,11 +17,18 @@ import de.bixilon.kotlinglm.vec2.Vec2
|
||||
import de.bixilon.minosoft.gui.rendering.gui.test.GuiRenderTestUtil
|
||||
import de.bixilon.minosoft.gui.rendering.gui.test.GuiTestConsumer
|
||||
import org.testng.Assert.assertEquals
|
||||
import org.testng.Assert.assertFalse
|
||||
import org.testng.annotations.Test
|
||||
|
||||
@Test(groups = ["gui"])
|
||||
class ButtonElementTest {
|
||||
|
||||
fun `initial clean`() {
|
||||
val button = ButtonElement(GuiRenderTestUtil.create(), "bc") { }
|
||||
assertFalse(button.update)
|
||||
}
|
||||
|
||||
|
||||
fun `basic verification`() {
|
||||
var invoked = 0
|
||||
val button = ButtonElement(GuiRenderTestUtil.create(), "bc") { invoked++ }
|
||||
|
@ -23,6 +23,7 @@ import de.bixilon.minosoft.gui.rendering.gui.test.GuiRenderTestUtil.assetSize
|
||||
import de.bixilon.minosoft.gui.rendering.gui.test.GuiTestConsumer
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4Util.marginOf
|
||||
import org.testng.Assert.assertEquals
|
||||
import org.testng.Assert.assertFalse
|
||||
import org.testng.annotations.Test
|
||||
|
||||
@Test(groups = ["font", "gui"])
|
||||
@ -33,6 +34,11 @@ class TextElementTest {
|
||||
element.assetSize(Vec2(0, 0))
|
||||
}
|
||||
|
||||
fun `initial clean`() {
|
||||
val element = TextElement(GuiRenderTestUtil.create(), "")
|
||||
assertFalse(element.update)
|
||||
}
|
||||
|
||||
fun `size of single char`() {
|
||||
val element = TextElement(GuiRenderTestUtil.create(), "b", background = null, properties = TextRenderProperties(shadow = false))
|
||||
element.assetSize(Vec2(0.5f, 11.0f))
|
||||
|
@ -18,6 +18,7 @@ import de.bixilon.kutil.latch.AbstractLatch
|
||||
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.shader.NativeShader
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.array.StaticTextureArray
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayStates
|
||||
@ -35,7 +36,7 @@ class DummyStaticTextureArray(renderSystem: RenderSystem) : StaticTextureArray {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean, properties: Boolean, default: (mipmaps: Boolean) -> Texture): Texture {
|
||||
override fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean, format: TextureFormats, properties: Boolean, default: (mipmaps: Boolean) -> Texture): Texture {
|
||||
return textures.getOrPut(resourceLocation) { DummyTexture() }
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.system.dummy.texture
|
||||
import de.bixilon.kotlinglm.vec2.Vec2
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.minosoft.gui.rendering.RenderContext
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayProperties
|
||||
@ -36,6 +37,6 @@ class DummyTexture : Texture {
|
||||
override var mipmaps: Boolean = false
|
||||
|
||||
override fun load(context: RenderContext) {
|
||||
data = TextureData(size, TextureGenerator.allocate(size))
|
||||
data = TextureData(size, TextureFormats.RGBA8, TextureGenerator.allocate(size, TextureFormats.RGBA8))
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 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.
|
||||
*
|
||||
@ -33,4 +33,14 @@ object ColorUtil {
|
||||
val color = (this * RGBColor.COLOR_FLOAT_DIVIDER).toInt()
|
||||
return color shl 16 or color shl 8 or color
|
||||
}
|
||||
|
||||
|
||||
fun rgba8ToRgba2(rgba8: Int): Byte {
|
||||
val red = (rgba8 shr 24 + 6) and 0x03
|
||||
val green = (rgba8 shr 16 + 6) and 0x03
|
||||
val blue = (rgba8 shr 8 + 6) and 0x03
|
||||
val alpha = (rgba8 shr 0 + 6) and 0x03
|
||||
|
||||
return ((red shl 6) or (green shl 4) or (blue shl 2) or alpha).toByte()
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FontProperties
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.PostInitFontType
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.empty.EmptyCodeRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.factory.FontTypeFactory
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
@ -73,7 +74,7 @@ class BitmapFontType(
|
||||
|
||||
private fun load(file: ResourceLocation, height: Int, ascent: Int, chars: List<String>, 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.createTexture(file, mipmaps = false, format = TextureFormats.RGBA2, properties = false)
|
||||
texture.load(context) // force load it, we need to calculate the width of every char
|
||||
|
||||
return load(texture, height, ascent, chars.codePoints())
|
||||
@ -82,7 +83,7 @@ class BitmapFontType(
|
||||
private fun ByteBuffer.scanLine(y: Int, width: Int, start: IntArray, end: IntArray) {
|
||||
for (index in 0 until (width * ROW)) {
|
||||
val pixelIndex = ((ROW * width * y) + index)
|
||||
val alpha = this[pixelIndex * 4 + 3].toInt() // index * rgba + a
|
||||
val alpha = this[pixelIndex].toInt() and 0x03 // index * rgba + a
|
||||
if (alpha == 0) {
|
||||
// transparent
|
||||
continue
|
||||
|
@ -26,6 +26,7 @@ import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FontProperties
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.PostInitFontType
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.factory.FontTypeFactory
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.unicode.UnicodeCodeRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.array.StaticTextureArray
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
|
||||
@ -84,7 +85,7 @@ class LegacyUnicodeFontType(
|
||||
sizes.skip(PAGE_SIZE.toLong())
|
||||
return
|
||||
}
|
||||
val texture = textures.createTexture(textureFile, mipmaps = false, properties = false)
|
||||
val texture = textures.createTexture(textureFile, mipmaps = false, format = TextureFormats.RGBA2, properties = false)
|
||||
|
||||
loadPage(pageId, texture, chars, sizes)
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import de.bixilon.minosoft.gui.rendering.RenderContext
|
||||
import de.bixilon.minosoft.gui.rendering.font.renderer.code.CodePointRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FontProperties
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.unicode.UnicodeCodeRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayProperties
|
||||
@ -39,7 +40,7 @@ class UnifontTexture(
|
||||
|
||||
override lateinit var array: TextureArrayProperties
|
||||
override lateinit var renderData: TextureRenderData
|
||||
override var data: TextureData = TextureData(size)
|
||||
override var data: TextureData = TextureData(size, TextureFormats.RGBA2)
|
||||
override var properties = ImageProperties.DEFAULT
|
||||
override val state: TextureStates = TextureStates.LOADED
|
||||
|
||||
@ -60,9 +61,9 @@ class UnifontTexture(
|
||||
}
|
||||
|
||||
private fun TextureData.set(row: Int, offset: Int, x: Int, y: Int) {
|
||||
val index = ((row * UnifontRasterizer.HEIGHT + y) * resolution + offset + x) * 4
|
||||
val index = (row * UnifontRasterizer.HEIGHT + y) * resolution + offset + x
|
||||
|
||||
buffer.putInt(index, 0xFFFFFFFF.toInt())
|
||||
buffer.put(index, 0xFF.toByte())
|
||||
}
|
||||
|
||||
private fun rasterize(row: Int, offset: Int, start: Int, end: Int, dataWidth: Int, data: ByteArray): CodePointRenderer {
|
||||
|
@ -60,7 +60,7 @@ open class ButtonElement(
|
||||
|
||||
init {
|
||||
padding = Vec4(4.0f)
|
||||
updateSize()
|
||||
tryUpdate()
|
||||
}
|
||||
|
||||
protected fun updateSize() {
|
||||
|
@ -17,12 +17,12 @@ import de.bixilon.kutil.cast.CastUtil.unsafeCast
|
||||
import de.bixilon.kutil.collections.CollectionUtil.lockMapOf
|
||||
import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedMap
|
||||
import de.bixilon.kutil.collections.map.LockMap
|
||||
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
|
||||
import de.bixilon.kutil.latch.SimpleLatch
|
||||
import de.bixilon.minosoft.config.key.KeyActions
|
||||
import de.bixilon.minosoft.config.key.KeyBinding
|
||||
import de.bixilon.minosoft.config.key.KeyCodes
|
||||
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.RenderUtil.runAsync
|
||||
import de.bixilon.minosoft.gui.rendering.gui.GUIElementDrawer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.gui.LayoutedGUIElement
|
||||
@ -69,7 +69,7 @@ class HUDManager(
|
||||
|
||||
for (builder in DEFAULT_ELEMENTS) {
|
||||
latch.inc()
|
||||
DefaultThreadPool += { registerElement(builder); latch.dec() }
|
||||
context.runAsync { registerElement(builder); latch.dec() }
|
||||
}
|
||||
latch.dec()
|
||||
latch.await()
|
||||
|
@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.sky.clouds
|
||||
import de.bixilon.minosoft.assets.AssetsManager
|
||||
import de.bixilon.minosoft.config.DebugOptions
|
||||
import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.readTexture
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
|
||||
import java.util.*
|
||||
@ -25,7 +26,7 @@ class CloudMatrix {
|
||||
|
||||
|
||||
fun load(assetsManager: AssetsManager) {
|
||||
val data = assetsManager[CLOUD_MATRIX].readTexture()
|
||||
val data = assetsManager[CLOUD_MATRIX].readTexture(TextureFormats.RGBA2) // TODO: luminance
|
||||
|
||||
if (data.size.x != CLOUD_MATRIX_SIZE || data.size.y != CLOUD_MATRIX_SIZE) {
|
||||
throw IllegalStateException("Cloud matrix has invalid size: ${data.size}")
|
||||
@ -35,7 +36,7 @@ class CloudMatrix {
|
||||
if (DebugOptions.CLOUD_RASTER) {
|
||||
matrix[i] = if ((i / CLOUD_MATRIX_SIZE) % 2 == 0) (i + 1) % 2 == 0 else (i % 2) == 0
|
||||
} else {
|
||||
matrix[i] = data.buffer.getInt(i * 4) ushr 24 == 0xFF
|
||||
matrix[i] = data.buffer.getInt(i) != 0x00
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.system.base.texture
|
||||
|
||||
enum class TextureFormats(val bytes: Int) {
|
||||
RGBA8(4),
|
||||
RGBA2(1),
|
||||
;
|
||||
}
|
@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture.array
|
||||
|
||||
import de.bixilon.kutil.latch.AbstractLatch
|
||||
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.sprite.SpriteAnimator
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.file.PNGTexture
|
||||
@ -26,7 +27,7 @@ interface StaticTextureArray : TextureArray {
|
||||
fun get(resourceLocation: ResourceLocation): Texture?
|
||||
|
||||
fun pushTexture(texture: Texture)
|
||||
fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean = true, properties: Boolean = true, default: (mipmaps: Boolean) -> Texture = { PNGTexture(resourceLocation, mipmaps = it) }): Texture
|
||||
fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean = true, format: TextureFormats = TextureFormats.RGBA8, properties: Boolean = true, default: (mipmaps: Boolean) -> Texture = { PNGTexture(resourceLocation, format = format, mipmaps = it) }): Texture
|
||||
|
||||
fun preLoad(latch: AbstractLatch)
|
||||
}
|
||||
|
@ -14,14 +14,16 @@
|
||||
package de.bixilon.minosoft.gui.rendering.system.base.texture.data
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
open class MipmapTextureData(
|
||||
size: Vec2i,
|
||||
format: TextureFormats,
|
||||
buffer: ByteBuffer,
|
||||
) : TextureData(size, buffer) {
|
||||
val mipmaps: Array<ByteBuffer> = OpenGLTextureUtil.generateMipMaps(buffer, size)
|
||||
) : TextureData(size, format, buffer) {
|
||||
val mipmaps: Array<ByteBuffer> = OpenGLTextureUtil.generateMipMaps(buffer, format, size)
|
||||
|
||||
override fun collect(): Array<ByteBuffer> = mipmaps
|
||||
}
|
||||
|
@ -14,15 +14,17 @@
|
||||
package de.bixilon.minosoft.gui.rendering.system.base.texture.data
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.memory.TextureGenerator
|
||||
import org.objenesis.ObjenesisStd
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
open class TextureData(
|
||||
val size: Vec2i,
|
||||
val buffer: ByteBuffer = TextureGenerator.allocate(size),
|
||||
val format: TextureFormats,
|
||||
val buffer: ByteBuffer = TextureGenerator.allocate(size, format),
|
||||
) {
|
||||
constructor(size: Vec2i, array: ByteArray) : this(size, ByteBuffer.wrap(array))
|
||||
constructor(size: Vec2i, format: TextureFormats, array: ByteArray) : this(size, format, ByteBuffer.wrap(array))
|
||||
|
||||
open fun collect(): Array<ByteBuffer> = arrayOf(buffer)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 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.
|
||||
*
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic
|
||||
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArray
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.data.TextureData
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.readTexture
|
||||
@ -25,6 +26,6 @@ interface DynamicTextureArray : TextureArray {
|
||||
fun pushBuffer(identifier: UUID, force: Boolean = false, data: () -> TextureData): DynamicTexture
|
||||
|
||||
fun pushRawArray(identifier: UUID, force: Boolean = false, data: () -> ByteArray): DynamicTexture {
|
||||
return pushBuffer(identifier, force) { ByteArrayInputStream(data()).readTexture() }
|
||||
return pushBuffer(identifier, force) { ByteArrayInputStream(data()).readTexture(TextureFormats.RGBA8) }
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import de.bixilon.minosoft.assets.AssetsManager
|
||||
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
|
||||
import de.bixilon.minosoft.data.entities.entities.player.properties.textures.metadata.SkinModel
|
||||
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
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.skin.PlayerSkin
|
||||
@ -65,7 +66,7 @@ class DefaultSkinProvider(
|
||||
}
|
||||
|
||||
private fun load(path: ResourceLocation): DynamicTexture? {
|
||||
val data = assets.getOrNull(path)?.readTexture() ?: return null
|
||||
val data = assets.getOrNull(path)?.readTexture(TextureFormats.RGBA8) ?: return null
|
||||
val texture = array.pushBuffer(UUID(0L, defaultId++.toLong()), true) { data }
|
||||
texture.usages.incrementAndGet()
|
||||
return texture
|
||||
|
@ -59,11 +59,11 @@ class SpriteTexture(private val original: Texture) : Texture {
|
||||
val bytesPerTexture = size.x * size.y * PNGDecoder.Format.RGBA.numComponents
|
||||
|
||||
for (i in 0 until animationProperties.frameCount) {
|
||||
val buffer = TextureGenerator.allocate(size)
|
||||
val buffer = TextureGenerator.allocate(size, data.format)
|
||||
buffer.copyFrom(original, bytesPerTexture * i, 0, bytesPerTexture)
|
||||
buffer.flip()
|
||||
|
||||
val splitTexture = MemoryTexture(size, mipmaps = true, buffer = buffer)
|
||||
val splitTexture = MemoryTexture(size, mipmaps = true, format = data.format, buffer = buffer)
|
||||
|
||||
splitTextures += splitTexture
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture.texture
|
||||
import de.bixilon.kotlinglm.vec2.Vec2
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.minosoft.gui.rendering.RenderContext
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayProperties
|
||||
@ -52,7 +53,7 @@ interface Texture : ShaderTexture {
|
||||
return renderData.transformUV(end)
|
||||
}
|
||||
|
||||
fun createData(mipmaps: Boolean = this.mipmaps, size: Vec2i, buffer: ByteBuffer): TextureData {
|
||||
return if (mipmaps) MipmapTextureData(size, buffer) else TextureData(size, buffer)
|
||||
fun createData(mipmaps: Boolean = this.mipmaps, size: Vec2i, format: TextureFormats, buffer: ByteBuffer): TextureData {
|
||||
return if (mipmaps) MipmapTextureData(size, format, buffer) else TextureData(size, format, buffer)
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.minosoft.assets.AssetsManager
|
||||
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayProperties
|
||||
@ -34,6 +35,7 @@ import java.io.FileNotFoundException
|
||||
class PNGTexture(
|
||||
override val resourceLocation: ResourceLocation,
|
||||
override var mipmaps: Boolean = true,
|
||||
val format: TextureFormats = TextureFormats.RGBA8,
|
||||
) : FileTexture {
|
||||
override lateinit var renderData: TextureRenderData
|
||||
|
||||
@ -57,17 +59,17 @@ class PNGTexture(
|
||||
}
|
||||
|
||||
var data = try {
|
||||
assetsManager[resourceLocation].readTexture()
|
||||
assetsManager[resourceLocation].readTexture(format)
|
||||
} catch (error: Throwable) {
|
||||
state = TextureStates.ERRORED
|
||||
Log.log(LogMessageType.RENDERING, LogLevels.WARN) { "Can not load texture $resourceLocation: $error" }
|
||||
if (error !is FileNotFoundException) {
|
||||
Log.log(LogMessageType.RENDERING, LogLevels.VERBOSE) { error }
|
||||
}
|
||||
assetsManager[RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION].readTexture()
|
||||
assetsManager[RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION].readTexture(format)
|
||||
}
|
||||
data.buffer.rewind()
|
||||
if (mipmaps) data = MipmapTextureData(data.size, data.buffer)
|
||||
if (mipmaps) data = MipmapTextureData(data.size, format, data.buffer)
|
||||
|
||||
this.size = data.size
|
||||
transparency = TextureTransparencies.OPAQUE
|
||||
|
@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.rendering.system.base.texture.texture.memory
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.minosoft.gui.rendering.RenderContext
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureStates
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.array.TextureArrayProperties
|
||||
@ -28,16 +29,17 @@ class MemoryTexture(
|
||||
override val size: Vec2i,
|
||||
override var properties: ImageProperties = ImageProperties(),
|
||||
override var mipmaps: Boolean = true,
|
||||
format: TextureFormats,
|
||||
buffer: ByteBuffer,
|
||||
) : Texture {
|
||||
override lateinit var array: TextureArrayProperties
|
||||
override lateinit var renderData: TextureRenderData
|
||||
override var transparency: TextureTransparencies = TextureTransparencies.OPAQUE
|
||||
private set
|
||||
override var data: TextureData = createData(mipmaps, size, buffer)
|
||||
override var data: TextureData = createData(mipmaps, size, format, buffer)
|
||||
|
||||
init {
|
||||
if (buffer.limit() != TextureGenerator.getBufferSize(size)) throw IllegalArgumentException("Invalid buffer size: ${buffer.limit()}")
|
||||
if (buffer.limit() != TextureGenerator.getBufferSize(size, format)) throw IllegalArgumentException("Invalid buffer size: ${buffer.limit()}")
|
||||
}
|
||||
|
||||
override val state: TextureStates = TextureStates.LOADED
|
||||
|
@ -14,12 +14,14 @@
|
||||
package de.bixilon.minosoft.gui.rendering.system.base.texture.texture.memory
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.matthiasmann.twl.utils.PNGDecoder
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import org.lwjgl.BufferUtils
|
||||
|
||||
object TextureGenerator {
|
||||
|
||||
fun getBufferSize(size: Vec2i) = size.x * size.y * PNGDecoder.Format.RGBA.numComponents
|
||||
fun getBufferSize(size: Vec2i, bytes: Int) = size.x * size.y * bytes
|
||||
fun getBufferSize(size: Vec2i, format: TextureFormats) = getBufferSize(size, format.bytes)
|
||||
|
||||
fun allocate(size: Vec2i) = BufferUtils.createByteBuffer(getBufferSize(size))
|
||||
fun allocate(size: Vec2i, bytes: Int) = BufferUtils.createByteBuffer(getBufferSize(size, bytes))
|
||||
fun allocate(size: Vec2i, format: TextureFormats) = allocate(size, format.bytes)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 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.
|
||||
*
|
||||
@ -24,7 +24,7 @@ abstract class OpenGLTexture {
|
||||
abstract fun init()
|
||||
|
||||
fun bind(target: Int) {
|
||||
check(target in 0 until 12)
|
||||
check(target in 0 until 16)
|
||||
glActiveTexture(GL_TEXTURE0 + target)
|
||||
glBindTexture(GL_TEXTURE_2D, id)
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import de.bixilon.minosoft.assets.util.InputStreamUtil.readAsString
|
||||
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.RenderContext
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.shader.NativeShader
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
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
|
||||
@ -32,6 +33,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.data.TextureData
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.sprite.SpriteAnimator
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.sprite.SpriteTexture
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture
|
||||
import de.bixilon.minosoft.gui.rendering.system.opengl.texture.OpenGLTextureUtil.gl
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureAnimation
|
||||
import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
@ -73,7 +75,7 @@ class OpenGLTextureArray(
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean, properties: Boolean, default: (mipmaps: Boolean) -> Texture): Texture {
|
||||
override fun createTexture(resourceLocation: ResourceLocation, mipmaps: Boolean, format: TextureFormats, properties: Boolean, default: (mipmaps: Boolean) -> Texture): Texture {
|
||||
namedTextures[resourceLocation]?.let { return it }
|
||||
|
||||
// load .mcmeta
|
||||
@ -189,7 +191,7 @@ class OpenGLTextureArray(
|
||||
for ((level, data) in texture.data.collect().withIndex()) {
|
||||
val size = texture.size shr level
|
||||
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, renderData.index, size.x, size.y, 1, GL_RGBA, GL_UNSIGNED_BYTE, data)
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, renderData.index, size.x, size.y, 1, texture.data.format.gl, GL_UNSIGNED_BYTE, data)
|
||||
}
|
||||
|
||||
texture.data = TextureData.NULL
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 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.
|
||||
*
|
||||
@ -14,6 +14,7 @@
|
||||
package de.bixilon.minosoft.gui.rendering.system.opengl.texture
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import example.jonathan2520.SRGBAverager
|
||||
import org.lwjgl.BufferUtils
|
||||
import org.lwjgl.opengl.GL11.*
|
||||
@ -38,7 +39,8 @@ object OpenGLTextureUtil {
|
||||
return textureId
|
||||
}
|
||||
|
||||
fun generateMipMaps(data: ByteBuffer, size: Vec2i): Array<ByteBuffer> {
|
||||
fun generateMipMaps(data: ByteBuffer, format: TextureFormats, size: Vec2i): Array<ByteBuffer> {
|
||||
if (format != TextureFormats.RGBA8) TODO("Mipmap only supports rgba8 atm.")
|
||||
val images: MutableList<ByteBuffer> = mutableListOf()
|
||||
|
||||
images += data
|
||||
@ -93,4 +95,11 @@ object OpenGLTextureUtil {
|
||||
buffer.position(0)
|
||||
return buffer
|
||||
}
|
||||
|
||||
|
||||
val TextureFormats.gl: Int
|
||||
get() = when (this) {
|
||||
TextureFormats.RGBA8 -> GL_RGBA8
|
||||
TextureFormats.RGBA2 -> GL_RGBA2
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ class OpenGLDynamicTextureArray(
|
||||
Log.log(LogMessageType.ASSETS, LogLevels.WARN) { "Dynamic texture $texture, has not a size of ${resolution}x${resolution}!" }
|
||||
}
|
||||
|
||||
val mipmaps = OpenGLTextureUtil.generateMipMaps(data.buffer, data.size)
|
||||
val mipmaps = OpenGLTextureUtil.generateMipMaps(data.buffer, data.format, data.size)
|
||||
texture.data = mipmaps
|
||||
texture.size = data.size
|
||||
if (force) {
|
||||
|
@ -15,12 +15,15 @@ package de.bixilon.minosoft.gui.rendering.textures
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
|
||||
import de.bixilon.minosoft.data.text.formatting.color.ColorUtil
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureFormats
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.array.StaticTextureArray
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.data.TextureData
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture
|
||||
import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh
|
||||
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
||||
import de.bixilon.minosoft.util.KUtil.getRGBA
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
import de.matthiasmann.twl.utils.PNGDecoder
|
||||
import org.lwjgl.BufferUtils
|
||||
@ -29,6 +32,7 @@ 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 TextureUtil {
|
||||
@ -91,7 +95,7 @@ object TextureUtil {
|
||||
* Only happens to some weird textures (seen in PureBDCraft)
|
||||
* Ignores the alpha channel
|
||||
*/
|
||||
private fun InputStream.readTexture2(): TextureData {
|
||||
private fun InputStream.readTexture2(format: TextureFormats): TextureData {
|
||||
val image: BufferedImage = ImageIO.read(this)
|
||||
val rgb = image.getRGB(0, 0, image.width, image.height, null, 0, image.width)
|
||||
|
||||
@ -99,25 +103,46 @@ object TextureUtil {
|
||||
val dataOutput = DataOutputStream(byteOutput)
|
||||
|
||||
for (color in rgb) {
|
||||
dataOutput.writeInt((color shl 8) or 0xFF)
|
||||
val rgba = (color shl 8) or 0xFF
|
||||
when (format) {
|
||||
TextureFormats.RGBA8 -> dataOutput.writeInt(rgba)
|
||||
TextureFormats.RGBA2 -> dataOutput.writeByte(ColorUtil.rgba8ToRgba2(rgba).toInt())
|
||||
}
|
||||
}
|
||||
|
||||
val buffer = MemoryUtil.memAlloc(byteOutput.size())
|
||||
buffer.put(byteOutput.toByteArray())
|
||||
|
||||
return TextureData(Vec2i(image.width, image.height), buffer)
|
||||
return TextureData(Vec2i(image.width, image.height), format, buffer)
|
||||
}
|
||||
|
||||
fun InputStream.readTexture(): TextureData {
|
||||
return try {
|
||||
fun InputStream.readTexture(format: TextureFormats): TextureData {
|
||||
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)
|
||||
|
||||
TextureData(Vec2i(decoder.width, decoder.height), data)
|
||||
} catch (exception: Throwable) {
|
||||
this.reset()
|
||||
readTexture2()
|
||||
|
||||
val converted = when (format) {
|
||||
TextureFormats.RGBA8 -> data
|
||||
TextureFormats.RGBA2 -> data.copyRgba8ToRgba2()
|
||||
}
|
||||
return TextureData(Vec2i(decoder.width, decoder.height), format, converted)
|
||||
} catch (_: Throwable) {
|
||||
}
|
||||
this.reset()
|
||||
return readTexture2(format)
|
||||
}
|
||||
|
||||
|
||||
private fun ByteBuffer.copyRgba8ToRgba2(): ByteBuffer {
|
||||
val next = BufferUtils.createByteBuffer(this.limit() / 4)
|
||||
|
||||
for (index in 0..next.limit()) {
|
||||
val rgba = this.getRGBA(index)
|
||||
next.put(index, ColorUtil.rgba8ToRgba2(rgba))
|
||||
}
|
||||
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ import de.bixilon.minosoft.util.url.ResourceURLHandler
|
||||
import io.netty.channel.SimpleChannelInboundHandler
|
||||
import javafx.application.Platform
|
||||
import org.kamranzafar.jtar.TarHeader
|
||||
import java.nio.ByteBuffer
|
||||
import java.security.SecureRandom
|
||||
import java.util.*
|
||||
import javax.net.ssl.SSLContext
|
||||
@ -352,4 +353,16 @@ object KUtil {
|
||||
inline fun <reified T : Enum<T>> ValuesEnum<T>.set(): EnumSet<T> {
|
||||
return EnumSetUtil.create(T::class.java, VALUES)
|
||||
}
|
||||
|
||||
fun ByteBuffer.getRGB(index: Int): Int {
|
||||
val red: Int = this[index].toInt() and 0xFF
|
||||
val green: Int = this[index + 1].toInt() and 0xFF
|
||||
val blue: Int = this[index + 2].toInt() and 0xFF
|
||||
|
||||
return 0xFF shl 24 or (red shl 16) or (green shl 8) or blue
|
||||
}
|
||||
|
||||
fun ByteBuffer.getRGBA(index: Int): Int {
|
||||
return (getRGB(index) shl 8) or (this[index + 3].toInt() and 0x0FF)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user