All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
jvmMain.ru.casperix.multiplatform.text.PixelFontBuilder.kt Maven / Gradle / Ivy
package ru.casperix.multiplatform.text
import ru.casperix.multiplatform.font.FontReference
import ru.casperix.multiplatform.font.localize.CharacterSets
import ru.casperix.multiplatform.font.pixel.PixelFont
import ru.casperix.multiplatform.font.pixel.PixelFontSymbol
import ru.casperix.multiplatform.pixel_map.PixelMapRegion
import ru.casperix.multiplatform.loader.JvmImageConverter
import ru.casperix.math.vector.int32.Vector2i
import ru.casperix.renderer.material.*
import java.awt.*
import java.awt.font.FontRenderContext
import java.awt.font.GlyphVector
import java.awt.image.BufferedImage
import kotlin.math.roundToInt
@ExperimentalUnsignedTypes
object PixelFontBuilder {
val antiAlias = true
val bicubicInterpolation = true
val subpixelRender = false
class SymbolInfo(val char: Char, val size: Vector2i, val image: BufferedImage?)
fun build(reference: FontReference, chars: Collection): PixelFont {
val awtFont = Font(reference.name, Font.PLAIN, reference.size)
val awtMetrics = createTempGraphic().getFontMetrics(awtFont)
val metrics = getFontMetrics(awtFont)
val baselineOffset = Vector2i(0, - awtMetrics.ascent.toFloat().roundToInt())
val config = TextureConfig(TextureFilter.NEAREST, TextureFilter.NEAREST, TextureWrap.CLAMP, TextureWrap.CLAMP, TextureWrap.CLAMP, false, false)
val symbols = chars.mapNotNull { char ->
getSymbolInfo(awtFont, char, awtMetrics)
}.map {
val graphic = if (it.image != null) {
val pixelMap = JvmImageConverter.createPixelMap(it.image, reference.name + ":" + reference.size)
PixelMapRegion(Texture2D( pixelMap, config))
} else null
PixelFontSymbol(it.char, baselineOffset, it.size, graphic)
}
return PixelFont(reference, metrics, symbols)
}
private fun createTempGraphic(): Graphics2D {
/* Creating temporary image to extract character size */
val tempImage = BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)
val tempGraphic = tempImage.createGraphics()
applyHints(tempGraphic)
return tempGraphic
}
private fun getFontMetrics(font: Font): ru.casperix.multiplatform.font.FontMetrics {
val tempGraphic = createTempGraphic()
val awtMetrics = tempGraphic.getFontMetrics(font)
val frc: FontRenderContext = tempGraphic.fontRenderContext
val gv: GlyphVector = font.createGlyphVector(frc, CharacterSets.en.chars)
val bounds = gv.getPixelBounds(null, 0f, 0f)
val ascent = -bounds.y.toFloat()//awtMetrics.ascent.toFloat()
val descent = awtMetrics.descent.toFloat()
val leading = awtMetrics.leading.toFloat() + (awtMetrics.ascent.toFloat() - ascent)
return ru.casperix.multiplatform.font.FontMetrics(ascent, descent, leading)
}
private fun applyHints(graphic: Graphics2D) = graphic.apply {
if (antiAlias) {
setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
}
if (bicubicInterpolation) {
setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC)
}
setRenderingHint(
RenderingHints.KEY_FRACTIONALMETRICS, if (subpixelRender) {
RenderingHints.VALUE_FRACTIONALMETRICS_ON
} else {
RenderingHints.VALUE_FRACTIONALMETRICS_OFF
}
)
}
private fun getSymbolInfo(font: Font, c: Char, metrics: FontMetrics): SymbolInfo? {
/* Get char charWidth and charHeight */
val charWidth = metrics.charWidth(c)
val charHeight = metrics.height
val symbolSize = Vector2i(charWidth, charHeight)
/* Check if charWidth is 0 */
if (charWidth == 0 || charHeight == 0) {
return null
}
if (!font.canDisplay(c)) {
return SymbolInfo(c, symbolSize, null)
}
/* Create image for holding the char */
val image = BufferedImage(charWidth, charHeight, BufferedImage.TYPE_INT_ARGB)
val graphic = image.createGraphics()
applyHints(graphic)
graphic.font = font
graphic.paint = Color.WHITE
graphic.drawString(c.toString(), 0, metrics.ascent)
// graphic.paint = Color.RED
// graphic.drawRect(0, 0, charWidth, charHeight)
//
// val frc = FontRenderContext(AffineTransform(), true, false)
// val vector = font.layoutGlyphVector(
// frc,
// charArrayOf( c),
// 0,
// 1,
// Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT
// )
// graphic.drawGlyphVector(vector, 0f, metrics.ascent.toFloat())
graphic.dispose()
return SymbolInfo(c, symbolSize, image)
}
}