mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 09:56:37 -04:00
wip bitmap font loading + tests
This commit is contained in:
parent
ce3a678d39
commit
1a6b8d04a7
@ -0,0 +1,75 @@
|
||||
package de.bixilon.minosoft.gui.rendering.font.types.bitmap
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2
|
||||
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.empty.EmptyCodeRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
||||
import de.bixilon.minosoft.gui.rendering.system.dummy.texture.DummyTexture
|
||||
import org.testng.Assert.*
|
||||
import org.testng.annotations.Test
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.stream.IntStream
|
||||
import kotlin.reflect.full.companionObject
|
||||
|
||||
|
||||
@Test(groups = ["font"])
|
||||
class BitmapFontTypeTest {
|
||||
private val LOAD = BitmapFontType::class.companionObject!!.java.getDeclaredMethod("load", AbstractTexture::class.java, Int::class.java, Int::class.java, Array<IntStream>::class.java).apply { isAccessible = true }
|
||||
|
||||
private fun createTexture(start: IntArray, end: IntArray, width: Int, height: Int): AbstractTexture {
|
||||
check(start.size == end.size)
|
||||
|
||||
val buffer = ByteBuffer.allocate((start.size / 16 + 1) * 16 * width * height * 4)
|
||||
|
||||
for (row in 0..start.size / 16) {
|
||||
for (char in 0 until 16) {
|
||||
val start = start.getOrNull((row * 16) + char) ?: 0
|
||||
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 {
|
||||
buffer.put(0x00.toByte())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val texture = DummyTexture(minosoft("test"))
|
||||
texture.data = buffer
|
||||
|
||||
return texture
|
||||
}
|
||||
|
||||
private fun load(start: IntArray, end: IntArray, width: Int = 8, height: Int = 8, ascent: Int = 8, chars: Array<IntArray>): BitmapFontType {
|
||||
val texture = createTexture(start, end, width, height)
|
||||
|
||||
val fontType = LOAD(BitmapFontType, texture, height, ascent, chars.map { IntStream.of(*it) }.toTypedArray()) as BitmapFontType
|
||||
|
||||
|
||||
return fontType
|
||||
}
|
||||
|
||||
fun `space size`() {
|
||||
val font = load(intArrayOf(), intArrayOf(), chars = arrayOf(intArrayOf('a'.code)))
|
||||
|
||||
val a = font['a'.code]!! as EmptyCodeRenderer
|
||||
assertEquals(a.width, 4)
|
||||
}
|
||||
|
||||
fun `load basic with default options`() {
|
||||
val font = load(intArrayOf(1, 2, 3), intArrayOf(7, 4, 6), chars = arrayOf(intArrayOf('a'.code, 'b'.code, 'c'.code)))
|
||||
|
||||
val a = font['a'.code]!! as BitmapCodeRenderer
|
||||
assertEquals(a.width, 7)
|
||||
assertEquals(a.uvStart, Vec2(0.0078125, 0))
|
||||
assertEquals(a.uvEnd, Vec2(0.0625, 0))
|
||||
|
||||
// TODO
|
||||
}
|
||||
}
|
@ -35,9 +35,7 @@ class DummyTexture(
|
||||
override val transparency: TextureTransparencies get() = TextureTransparencies.OPAQUE
|
||||
override var properties: ImageProperties = ImageProperties()
|
||||
override var renderData: TextureRenderData = DummyTextureRenderData
|
||||
override var data: ByteBuffer?
|
||||
get() = TODO("Not yet implemented")
|
||||
set(value) {}
|
||||
override var data: ByteBuffer? = null
|
||||
override var mipmapData: Array<ByteBuffer>?
|
||||
get() = TODO("Not yet implemented")
|
||||
set(value) {}
|
||||
|
@ -17,5 +17,5 @@ import de.bixilon.kutil.latch.AbstractLatch
|
||||
|
||||
interface PostInitFontType : FontType {
|
||||
|
||||
fun postInit(latch: AbstractLatch) = Unit
|
||||
fun postInit(latch: AbstractLatch)
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ class BitmapCodeRenderer(
|
||||
override var uvStart: Vec2,
|
||||
override var uvEnd: Vec2,
|
||||
override val width: Float,
|
||||
val ascent1: Int,
|
||||
) : RasterizedCodePointRenderer, AscentedCodePointRenderer {
|
||||
override val ascent: Float
|
||||
get() = 1.0f
|
||||
|
@ -13,31 +13,47 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.font.types.bitmap
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2
|
||||
import de.bixilon.kutil.json.JsonObject
|
||||
import de.bixilon.kutil.latch.AbstractLatch
|
||||
import de.bixilon.kutil.primitive.IntUtil.toInt
|
||||
import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft
|
||||
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.RenderContext
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.FontType
|
||||
import de.bixilon.minosoft.gui.rendering.font.renderer.code.CodePointRenderer
|
||||
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.texture.AbstractTexture
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.stream.IntStream
|
||||
|
||||
class BitmapFontType(
|
||||
val chars: Int2ObjectOpenHashMap<BitmapCodeRenderer>,
|
||||
) : FontType {
|
||||
val chars: Int2ObjectOpenHashMap<CodePointRenderer>,
|
||||
) : PostInitFontType {
|
||||
|
||||
init {
|
||||
chars.trim()
|
||||
}
|
||||
|
||||
override fun get(codePoint: Int): BitmapCodeRenderer {
|
||||
override fun get(codePoint: Int): CodePointRenderer? {
|
||||
return chars[codePoint]
|
||||
}
|
||||
|
||||
override fun postInit(latch: AbstractLatch) {
|
||||
for (char in chars.values) {
|
||||
if (char !is BitmapCodeRenderer) continue
|
||||
char.updateArray()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object : FontTypeFactory<BitmapFontType> {
|
||||
private const val ROW = 16
|
||||
override val identifier = minecraft("bitmap")
|
||||
|
||||
override fun build(context: RenderContext, data: JsonObject): BitmapFontType? {
|
||||
@ -48,12 +64,78 @@ class BitmapFontType(
|
||||
return load(file, height, ascent, chars, context)
|
||||
}
|
||||
|
||||
private fun List<String>.codePoints(): Array<IntStream> {
|
||||
return this.map { it.codePoints() }.toTypedArray()
|
||||
}
|
||||
|
||||
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.textureManager.staticTextures.createTexture(file)
|
||||
texture.load(context.connection.assetsManager) // force load it, we need to calculate the width of every char
|
||||
|
||||
return load(texture, height, ascent, chars.codePoints())
|
||||
}
|
||||
|
||||
private fun ByteBuffer.scanLine(y: Int, width: Int, start: IntArray, end: IntArray) {
|
||||
for (index in 0 until (width * ROW)) {
|
||||
val alpha = this[(((ROW * width) * y) + index) * 4 + 3].toInt()
|
||||
if (alpha == 0) {
|
||||
// transparent
|
||||
continue
|
||||
}
|
||||
|
||||
val char = index / width
|
||||
val pixel = index % width
|
||||
|
||||
start[char] = minOf(start[char], pixel)
|
||||
end[char] = maxOf(end[char], pixel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createRenderer(texture: AbstractTexture, row: Int, column: Int, start: Int, end: Int, height: Int, ascent: Int): CodePointRenderer {
|
||||
if (end < start) return EmptyCodeRenderer()
|
||||
|
||||
val uvStart = Vec2()
|
||||
val uvEnd = Vec2(0.1f)
|
||||
|
||||
val width = 1.0f
|
||||
|
||||
|
||||
// TODO
|
||||
return null
|
||||
|
||||
return BitmapCodeRenderer(texture, uvStart, uvEnd, width, ascent)
|
||||
}
|
||||
|
||||
private fun load(texture: AbstractTexture, height: Int, ascent: Int, chars: Array<IntStream>): BitmapFontType? {
|
||||
val rows = chars.size
|
||||
val width = texture.size.x / ROW
|
||||
|
||||
val start = IntArray(ROW) { width }
|
||||
val end = IntArray(ROW)
|
||||
|
||||
val renderer = Int2ObjectOpenHashMap<CodePointRenderer>()
|
||||
|
||||
for (row in 0 until rows) {
|
||||
val iterator = chars[row].iterator()
|
||||
|
||||
for (pixel in 0 until height) {
|
||||
texture.data!!.scanLine(row + pixel, width, start, end)
|
||||
}
|
||||
|
||||
var column = 0
|
||||
while (iterator.hasNext()) {
|
||||
val codePoint = iterator.nextInt()
|
||||
renderer[codePoint] = createRenderer(texture, row, column, start[column], end[column], height, ascent)
|
||||
column++
|
||||
}
|
||||
|
||||
start.fill(width); end.fill(0) // fill with maximum values again
|
||||
}
|
||||
|
||||
texture.data!!.rewind()
|
||||
|
||||
if (renderer.isEmpty()) return null
|
||||
return BitmapFontType(renderer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
||||
|
||||
data class EmptyCodeRenderer(
|
||||
val width: Int,
|
||||
val width: Int = 4,
|
||||
) : CodePointRenderer {
|
||||
|
||||
init {
|
||||
|
Loading…
x
Reference in New Issue
Block a user