commonMain.ru.casperix.multiplatform.font.pixel.PixelFontPacker.kt Maven / Gradle / Ivy
package ru.casperix.multiplatform.font.pixel
import ru.casperix.multiplatform.font.FontReference
import ru.casperix.multiplatform.pixel_map.PixelMapRegion
import ru.casperix.multiplatform.loader.resourceLoader
import ru.casperix.math.axis_aligned.int32.Box2i
import ru.casperix.math.color.Colors
import ru.casperix.math.vector.int32.Vector2i
import ru.casperix.multiplatform.rectangle_packer.RectanglePacker
import ru.casperix.multiplatform.rectangle_packer.RectangleSource
import ru.casperix.renderer.material.Texture2D
import ru.casperix.renderer.pixel_map.PixelMap
import ru.casperix.multiplatform.text.TextRenderConfig.debugDrawFontAtlas
import ru.casperix.multiplatform.text.TextRenderConfig.debugSaveFontAtlas
import ru.casperix.multiplatform.util.PixelMapDrawer
@ExperimentalUnsignedTypes
object PixelFontPacker {
fun packFont(font: PixelFont): PixelFont {
val symbols = font.symbols
val withGraphic = symbols.filter { it.graphic != null }
val withoutGraphic = symbols.filter { it.graphic == null }
val packedSymbols = packGraphicSymbols(font.reference, withGraphic)
return PixelFont(font.reference, font.metrics, packedSymbols + withoutGraphic)
}
private fun packGraphicSymbols(reference: FontReference, symbols: Collection): Collection {
val containers = symbols.map {
RectangleSource(it, it.size)
}
val packed = RectanglePacker.pack(containers)
?: throw Exception("Cant pack items")
val atlas = PixelMap.RGBA(packed.dimension)
packed.containers.forEach { container ->
val pixelRegion = container.source.graphic
?: throw Exception("Only graphic symbol must packed to atlas")
if (debugDrawFontAtlas) {
PixelMapDrawer.fillColor(
atlas,
container.position,
Colors.RED.toColor4b(),
pixelRegion.dimension,
false
)
PixelMapDrawer.fillColor(
atlas,
container.position + Vector2i.ONE,
Colors.BLUE.toColor4b(),
pixelRegion.dimension - Vector2i(2),
false
)
}
PixelMapDrawer.drawImage(
atlas,
container.position,
pixelRegion.atlas.map,
Vector2i.ZERO,
pixelRegion.region.dimension,
debugDrawFontAtlas
)
}
val packedSymbols = packed.containers.map { container ->
val original = container.source
val config = original.graphic!!.atlas.config
val graphic = PixelMapRegion(Texture2D( atlas, config), Box2i.byDimension(container.position, original.size))
original.copy(graphic = graphic)
}
if (debugSaveFontAtlas) {
val postfix = "_" + reference.name + "_" + reference.size
resourceLoader.saveImage("font_atlas$postfix.png", atlas)
}
return packedSymbols
}
}