package info.mechyrdia.lore
+import info.mechyrdia.Configuration
import info.mechyrdia.yieldThread
+import io.ktor.util.*
import java.awt.Font
import java.awt.RenderingHints
import java.awt.Shape
import java.awt.geom.GeneralPath
import java.awt.geom.PathIterator
import java.awt.image.BufferedImage
+import java.io.File
+import kotlin.properties.ReadOnlyProperty
+import kotlin.reflect.KProperty
+import kotlin.text.toCharArray
object MechyrdiaSansFont {
enum class Alignment(val amount: Double) {
private const val DEFAULT_FONT_SIZE = 48f
- private fun loadFont(font: String): Font {
- return Font
- .createFont(Font.TRUETYPE_FONT, javaClass.getResourceAsStream("/fonts/$font.ttf")!!)
- .deriveFont(DEFAULT_FONT_SIZE)
+ private val fontsRoot = File(Configuration.CurrentConfiguration.rootDir, "fonts")
+
+ private fun loadedFont(fontName: String): ReadOnlyProperty<Any?, Font> {
+ return object : ReadOnlyProperty<Any?, Font> {
+ private var loadedFont: Font? = null
+ private var lastLoaded = Long.MIN_VALUE
+
+ private val fontFile = fontsRoot.combineSafe("$fontName.ttf")
+
+ private fun loadFont(): Font = fontFile.inputStream().use { inStream ->
+ Font
+ .createFont(Font.TRUETYPE_FONT, inStream)
+ .deriveFont(DEFAULT_FONT_SIZE)
+ }
+
+ @Synchronized
+ override fun getValue(thisRef: Any?, property: KProperty<*>): Font {
+ val font = loadedFont
+ val lastMod = fontFile.lastModified()
+
+ if (font == null || lastLoaded < lastMod)
+ return loadFont().also {
+ loadedFont = it
+ lastLoaded = lastMod
+ }
+
+ return font
+ }
+ }
}
- private val mechyrdiaSans = loadFont("mechyrdia-sans")
- private val mechyrdiaSansB = loadFont("mechyrdia-sans-bold")
- private val mechyrdiaSansI = loadFont("mechyrdia-sans-italic")
- private val mechyrdiaSansBI = loadFont("mechyrdia-sans-bold-italic")
+ private val mechyrdiaSans by loadedFont("mechyrdia-sans")
+ private val mechyrdiaSansB by loadedFont("mechyrdia-sans-bold")
+ private val mechyrdiaSansI by loadedFont("mechyrdia-sans-italic")
+ private val mechyrdiaSansBI by loadedFont("mechyrdia-sans-bold-italic")
- private val mechyrdiaSansFonts = listOf(mechyrdiaSans, mechyrdiaSansI, mechyrdiaSansB, mechyrdiaSansBI)
+ private val mechyrdiaSansFonts = listOf(::mechyrdiaSans, ::mechyrdiaSansI, ::mechyrdiaSansB, ::mechyrdiaSansBI)
private fun getFont(bold: Boolean, italic: Boolean): Font {
- return mechyrdiaSansFonts[(if (bold) 2 else 0) + (if (italic) 1 else 0)]
+ return mechyrdiaSansFonts[(if (bold) 2 else 0) + (if (italic) 1 else 0)].get()
}
private fun layoutText(text: String, font: Font, alignAmount: Double): Shape {
if (line.isNotBlank()) {
val x = (width - fontMetrics.stringWidth(line)) * alignAmount
- // Mechyrdia Sans only supports the Latin alphabet, so we can ignore bidirectional text
+ // Mechyrdia Sans only supports the Latin and Cyrillic alphabets, so we can ignore bidirectional text
val glyphs = font.layoutGlyphVector(g2d.fontRenderContext, line.toCharArray(), 0, line.length, Font.LAYOUT_LEFT_TO_RIGHT)
val textShape = glyphs.outline as GeneralPath