mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 14:24:43 -04:00
Rewrite the font system to render the characters incrementally (#2635)
This commit is contained in:
parent
7330daff48
commit
4b6bab523f
@ -23,7 +23,8 @@ class AndroidLauncher : AndroidApplication() {
|
|||||||
val game = UncivGame (
|
val game = UncivGame (
|
||||||
version = BuildConfig.VERSION_NAME,
|
version = BuildConfig.VERSION_NAME,
|
||||||
crashReportSender = CrashReportSenderAndroid(this),
|
crashReportSender = CrashReportSenderAndroid(this),
|
||||||
exitEvent = this::finish
|
exitEvent = this::finish,
|
||||||
|
fontImplementation = NativeFontAndroid(45)
|
||||||
)
|
)
|
||||||
initialize(game, config)
|
initialize(game, config)
|
||||||
}
|
}
|
||||||
|
45
android/src/com/unciv/app/NativeFontAndroid.kt
Executable file
45
android/src/com/unciv/app/NativeFontAndroid.kt
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
package com.unciv.app
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Paint
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
|
import com.unciv.ui.utils.NativeFontImplementation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tian on 2016/10/2.
|
||||||
|
*/
|
||||||
|
class NativeFontAndroid(val size: Int) : NativeFontImplementation {
|
||||||
|
override fun getFontSize(): Int {
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCharPixmap(char: Char): Pixmap {
|
||||||
|
val paint = Paint()
|
||||||
|
paint.isAntiAlias = true
|
||||||
|
paint.textSize = size.toFloat()
|
||||||
|
val metric = paint.fontMetrics
|
||||||
|
var width = paint.measureText(char.toString()).toInt()
|
||||||
|
var height = (metric.descent - metric.ascent).toInt()
|
||||||
|
if (width == 0) {
|
||||||
|
height = size
|
||||||
|
width = height
|
||||||
|
}
|
||||||
|
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||||
|
val canvas = Canvas(bitmap)
|
||||||
|
paint.strokeWidth = 0f
|
||||||
|
paint.setARGB(255, 255, 255, 255)
|
||||||
|
canvas.drawText(char.toString(), 0f, -metric.ascent, paint)
|
||||||
|
val pixmap = Pixmap(width, height, Pixmap.Format.RGBA8888)
|
||||||
|
val data = IntArray(width * height)
|
||||||
|
bitmap.getPixels(data, 0, width, 0, 0, width, height)
|
||||||
|
for (i in 0 until width) {
|
||||||
|
for (j in 0 until height) {
|
||||||
|
pixmap.setColor(Integer.rotateLeft(data[i + (j * width)], 8))
|
||||||
|
pixmap.drawPixel(i, j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitmap.recycle()
|
||||||
|
return pixmap
|
||||||
|
}
|
||||||
|
}
|
@ -1,70 +0,0 @@
|
|||||||
package core.java.nativefont
|
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.Canvas
|
|
||||||
import android.graphics.Paint
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import com.badlogic.gdx.Gdx
|
|
||||||
import com.badlogic.gdx.backends.android.AndroidApplication
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
|
||||||
import com.badlogic.gdx.graphics.Pixmap
|
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by tian on 2016/10/2.
|
|
||||||
*/
|
|
||||||
class NativeFontAndroid : NativeFontListener {
|
|
||||||
private val fontFaces = HashMap<String, Typeface>()
|
|
||||||
private val androidApplication = Gdx.app as AndroidApplication
|
|
||||||
override fun getFontPixmap(txt: String, vpaint: NativeFontPaint): Pixmap {
|
|
||||||
val paint = Paint()
|
|
||||||
if (vpaint.tTFName != "") {
|
|
||||||
Gdx.app.log("app", Gdx.files.internal(vpaint.tTFName +
|
|
||||||
if (vpaint.tTFName.endsWith(".ttf")) "" else ".ttf").file().path)
|
|
||||||
val fontFace = Typeface.createFromAsset(androidApplication.assets, vpaint.tTFName +
|
|
||||||
if (vpaint.tTFName.endsWith(".ttf")) "" else ".ttf")
|
|
||||||
fontFaces[vpaint.tTFName] = fontFace
|
|
||||||
paint.typeface = fontFace
|
|
||||||
}
|
|
||||||
paint.isAntiAlias = true
|
|
||||||
paint.textSize = vpaint.textSize.toFloat()
|
|
||||||
val fm = paint.fontMetrics
|
|
||||||
var w = paint.measureText(txt).toInt()
|
|
||||||
var h = (fm.descent - fm.ascent).toInt()
|
|
||||||
if (w == 0) {
|
|
||||||
h = vpaint.textSize
|
|
||||||
w = h
|
|
||||||
}
|
|
||||||
var bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
|
|
||||||
var canvas: Canvas? = Canvas(bitmap)
|
|
||||||
// 如果是描边类型
|
|
||||||
if (vpaint.strokeColor != null) { // 绘制外层
|
|
||||||
paint.color = getColor(vpaint.strokeColor)
|
|
||||||
paint.strokeWidth = vpaint.strokeWidth.toFloat() // 描边宽度
|
|
||||||
paint.style = Paint.Style.FILL_AND_STROKE // 描边种类
|
|
||||||
paint.isFakeBoldText = true // 外层text采用粗体
|
|
||||||
canvas!!.drawText(txt, 0f, -fm.ascent, paint)
|
|
||||||
paint.isFakeBoldText = false
|
|
||||||
} else {
|
|
||||||
paint.isUnderlineText = vpaint.underlineText
|
|
||||||
paint.isStrikeThruText = vpaint.strikeThruText
|
|
||||||
paint.isFakeBoldText = vpaint.fakeBoldText
|
|
||||||
}
|
|
||||||
// 绘制内层
|
|
||||||
paint.strokeWidth = 0f
|
|
||||||
paint.color = getColor(vpaint.color)
|
|
||||||
canvas!!.drawText(txt, 0f, -fm.ascent, paint)
|
|
||||||
val buffer = ByteArrayOutputStream()
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, buffer)
|
|
||||||
val encodedData = buffer.toByteArray()
|
|
||||||
val pixmap = Pixmap(encodedData, 0, encodedData.size)
|
|
||||||
buffer.close()
|
|
||||||
bitmap.recycle()
|
|
||||||
return pixmap
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getColor(color: Color?): Int {
|
|
||||||
return (color!!.a * 255.0f).toInt() shl 24 or ((color.r * 255.0f).toInt() shl 16) or ((color.g * 255.0f).toInt() shl 8) or (color.b * 255.0f).toInt()
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,7 +22,8 @@ class UncivGame(
|
|||||||
val version: String,
|
val version: String,
|
||||||
private val crashReportSender: CrashReportSender? = null,
|
private val crashReportSender: CrashReportSender? = null,
|
||||||
val exitEvent: (()->Unit)? = null,
|
val exitEvent: (()->Unit)? = null,
|
||||||
val cancelDiscordEvent: (()->Unit)? = null
|
val cancelDiscordEvent: (()->Unit)? = null,
|
||||||
|
val fontImplementation: NativeFontImplementation? = null
|
||||||
) : Game() {
|
) : Game() {
|
||||||
// we need this secondary constructor because Java code for iOS can't handle Kotlin lambda parameters
|
// we need this secondary constructor because Java code for iOS can't handle Kotlin lambda parameters
|
||||||
constructor(version: String) : this(version, null)
|
constructor(version: String) : this(version, null)
|
||||||
@ -94,7 +95,6 @@ class UncivGame(
|
|||||||
|
|
||||||
// This stuff needs to run on the main thread because it needs the GL context
|
// This stuff needs to run on the main thread because it needs the GL context
|
||||||
Gdx.app.postRunnable {
|
Gdx.app.postRunnable {
|
||||||
CameraStageBaseScreen.resetFonts()
|
|
||||||
ImageGetter.ruleset = RulesetCache.getBaseRuleset() // so that we can enter the map editor without having to load a game first
|
ImageGetter.ruleset = RulesetCache.getBaseRuleset() // so that we can enter the map editor without having to load a game first
|
||||||
thread(name="Music") { startMusic() }
|
thread(name="Music") { startMusic() }
|
||||||
restoreSize()
|
restoreSize()
|
||||||
|
@ -80,7 +80,6 @@ class LanguagePickerScreen(): PickerScreen(){
|
|||||||
game.settings.save()
|
game.settings.save()
|
||||||
|
|
||||||
game.translations.tryReadTranslationForCurrentLanguage()
|
game.translations.tryReadTranslationForCurrentLanguage()
|
||||||
resetFonts()
|
|
||||||
game.setScreen(MainMenuScreen())
|
game.setScreen(MainMenuScreen())
|
||||||
dispose()
|
dispose()
|
||||||
}
|
}
|
||||||
|
@ -70,19 +70,19 @@ open class CameraStageBaseScreen : Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var skin = Skin(Gdx.files.internal("skin/flat-earth-ui.json"))
|
val skin by lazy {
|
||||||
|
val skin = Skin(Gdx.files.internal("skin/flat-earth-ui.json"))
|
||||||
fun resetFonts(){
|
skin.get(TextButton.TextButtonStyle::class.java).font = Fonts.font.apply { data.setScale(20/45f) }
|
||||||
skin.get(TextButton.TextButtonStyle::class.java).font = Fonts.getFont(45).apply { data.setScale(20/45f) }
|
skin.get(CheckBox.CheckBoxStyle::class.java).font= Fonts.font.apply { data.setScale(20/45f) }
|
||||||
skin.get(CheckBox.CheckBoxStyle::class.java).font= Fonts.getFont(45).apply { data.setScale(20/45f) }
|
|
||||||
skin.get(Label.LabelStyle::class.java).apply {
|
skin.get(Label.LabelStyle::class.java).apply {
|
||||||
font = Fonts.getFont(45).apply { data.setScale(18/45f) }
|
font = Fonts.font.apply { data.setScale(18/45f) }
|
||||||
fontColor= Color.WHITE
|
fontColor= Color.WHITE
|
||||||
}
|
}
|
||||||
skin.get(TextField.TextFieldStyle::class.java).font = Fonts.getFont(45).apply { data.setScale(18/45f) }
|
skin.get(TextField.TextFieldStyle::class.java).font = Fonts.font.apply { data.setScale(18/45f) }
|
||||||
skin.get(SelectBox.SelectBoxStyle::class.java).font = Fonts.getFont(45).apply { data.setScale(20/45f) }
|
skin.get(SelectBox.SelectBoxStyle::class.java).font = Fonts.font.apply { data.setScale(20/45f) }
|
||||||
skin.get(SelectBox.SelectBoxStyle::class.java).listStyle.font = Fonts.getFont(45).apply { data.setScale(20/45f) }
|
skin.get(SelectBox.SelectBoxStyle::class.java).listStyle.font = Fonts.font.apply { data.setScale(20/45f) }
|
||||||
skin.get(CheckBox.CheckBoxStyle::class.java).fontColor= Color.WHITE
|
skin.get(CheckBox.CheckBoxStyle::class.java).fontColor= Color.WHITE
|
||||||
|
skin
|
||||||
}
|
}
|
||||||
internal var batch: Batch = SpriteBatch()
|
internal var batch: Batch = SpriteBatch()
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ fun String.toLabel(fontColor:Color= Color.WHITE, fontSize:Int=18): Label {
|
|||||||
if(fontColor!= Color.WHITE || fontSize!=18) { // if we want the default we don't need to create another style
|
if(fontColor!= Color.WHITE || fontSize!=18) { // if we want the default we don't need to create another style
|
||||||
labelStyle = Label.LabelStyle(labelStyle) // clone this to another
|
labelStyle = Label.LabelStyle(labelStyle) // clone this to another
|
||||||
labelStyle.fontColor = fontColor
|
labelStyle.fontColor = fontColor
|
||||||
if (fontSize != 18) labelStyle.font = Fonts.getFont(45)
|
if (fontSize != 18) labelStyle.font = Fonts.font
|
||||||
}
|
}
|
||||||
return Label(this.tr(),labelStyle).apply { setFontScale(fontSize/45f) }
|
return Label(this.tr(),labelStyle).apply { setFontScale(fontSize/45f) }
|
||||||
}
|
}
|
||||||
@ -249,7 +249,7 @@ fun Label.setFontColor(color:Color): Label {style=Label.LabelStyle(style).apply
|
|||||||
|
|
||||||
fun Label.setFontSize(size:Int): Label {
|
fun Label.setFontSize(size:Int): Label {
|
||||||
style = Label.LabelStyle(style)
|
style = Label.LabelStyle(style)
|
||||||
style.font = Fonts.getFont(45)
|
style.font = Fonts.font
|
||||||
style = style // because we need it to call the SetStyle function. Yuk, I know.
|
style = style // because we need it to call the SetStyle function. Yuk, I know.
|
||||||
return this.apply { setFontScale(size/45f) } // for chaining
|
return this.apply { setFontScale(size/45f) } // for chaining
|
||||||
}
|
}
|
@ -1,73 +1,103 @@
|
|||||||
package com.unciv.ui.utils
|
package com.unciv.ui.utils
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
|
import com.badlogic.gdx.graphics.Texture
|
||||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||||
|
import com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData
|
||||||
|
import com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph
|
||||||
|
import com.badlogic.gdx.graphics.g2d.GlyphLayout
|
||||||
|
import com.badlogic.gdx.graphics.g2d.PixmapPacker
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
|
import com.badlogic.gdx.utils.Array
|
||||||
|
import com.badlogic.gdx.utils.Disposable
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import core.java.nativefont.NativeFont
|
|
||||||
import core.java.nativefont.NativeFontPaint
|
|
||||||
|
|
||||||
object Fonts {
|
interface NativeFontImplementation {
|
||||||
// caches for memory and time saving
|
fun getFontSize(): Int
|
||||||
private val characterSetCache = HashMap<String, String>()
|
fun getCharPixmap(char: Char): Pixmap
|
||||||
private val fontCache = HashMap<String, BitmapFont>()
|
}
|
||||||
|
|
||||||
private fun getCharactersForFont(language: String = ""): String {
|
// This class is loosely based on libgdx's FreeTypeBitmapFontData
|
||||||
if (characterSetCache.containsKey(language)) return characterSetCache[language]!!
|
class NativeBitmapFontData(val fontImplementation: NativeFontImplementation) : BitmapFontData(), Disposable {
|
||||||
|
val regions: Array<TextureRegion>
|
||||||
|
|
||||||
val startTime = System.currentTimeMillis()
|
private var dirty = false
|
||||||
|
private val packer: PixmapPacker
|
||||||
|
|
||||||
// Basic Character Set - symbols missing from this will not be displayed, unless one of the
|
private val filter = Texture.TextureFilter.Linear
|
||||||
// 'complex' languages is chosen, in which case the translation file is used as character set as well.
|
|
||||||
// This means that for example user-set city names might not be displayed as entered.
|
|
||||||
// Missing Characters will be entirely invisible, not even take up horizontal space.
|
|
||||||
// Note that " (normal double quotes) and _ (underscore) _are_ such invisible characters.
|
|
||||||
val defaultText =
|
|
||||||
"AÀÁÀÄĂÂEÈÉÊĚÉÈIÌÍÏÍÎOÒÓÖÔÓÖƠUÙÚÜƯŮÚÜ" + // Latin uppercase vowels and similar symbols
|
|
||||||
"aäàâăäâąáeéèêęěèiìîìíoòöôöơóuùüưůûú" + // Latin lowercase vowels and similar symbols
|
|
||||||
"BCČĆDĐĎFGHJKLŁĹĽMNPQRŘŔSŠŚTŤVWXYÝZŽŻŹ" + // Latin uppercase consonants and similar symbols
|
|
||||||
"bcčćçdđďfghjklłĺľmnńňñpqrřŕsșšśtțťvwxyýzžżź" + // Latin lowercase consonants and similar symbols
|
|
||||||
"АБВГҐДЂЕЁЄЖЗЅИІЇЙЈКЛЉМНЊОПРСТЋУЎФХЦЧЏШЩЪЫЬЭЮЯабвгґдђеёєжзѕиіїйјклљмнњопрстћуўфхцчџшщъыьэюя" + // Russian
|
|
||||||
"ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωάßΆέΈέΉίϊΐΊόΌύΰϋΎΫΏ" + // Greek
|
|
||||||
"กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛" + // Thai
|
|
||||||
"İıÇŞşĞğ" + // Turkish
|
|
||||||
"øæå" + // Scandinavian
|
|
||||||
"ÃÕãõ" + // Portuguese
|
|
||||||
"şţșț" + // Romanian
|
|
||||||
"1234567890" +
|
|
||||||
"‘?ʼ’'“!”(%)[#]{@}/&\\<-+÷×=>®©\$€£¥¢:;,.…¡*|«»—∞✘✔"
|
|
||||||
val charSet = HashSet<Char>()
|
|
||||||
charSet.addAll(defaultText.asIterable())
|
|
||||||
|
|
||||||
if (language != "") {
|
init {
|
||||||
for (entry in UncivGame.Current.translations.entries) {
|
// set general font data
|
||||||
for (lang in entry.value) {
|
flipped = false
|
||||||
if (lang.key == language) charSet.addAll(lang.value.asIterable())
|
lineHeight = fontImplementation.getFontSize().toFloat()
|
||||||
}
|
capHeight = lineHeight
|
||||||
}
|
ascent = -lineHeight
|
||||||
}
|
down = -lineHeight
|
||||||
val characterSetString = charSet.joinToString("")
|
|
||||||
characterSetCache[language] = characterSetString
|
|
||||||
|
|
||||||
val totalTime = System.currentTimeMillis() - startTime
|
// Create a packer.
|
||||||
println("Loading characters for font - " + totalTime + "ms")
|
val size = 1024
|
||||||
|
val packStrategy = PixmapPacker.GuillotineStrategy()
|
||||||
|
packer = PixmapPacker(size, size, Pixmap.Format.RGBA8888, 1, false, packStrategy)
|
||||||
|
packer.transparentColor = Color.WHITE
|
||||||
|
packer.transparentColor.a = 0f
|
||||||
|
|
||||||
return characterSetString
|
// Generate texture regions.
|
||||||
|
regions = Array()
|
||||||
|
packer.updateTextureRegions(regions, filter, filter, false)
|
||||||
|
|
||||||
|
// Set space glyph.
|
||||||
|
val spaceGlyph = getGlyph(' ')
|
||||||
|
spaceXadvance = spaceGlyph.xadvance.toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFont(size: Int): BitmapFont {
|
override fun getGlyph(ch: Char): Glyph {
|
||||||
val language = UncivGame.Current.settings.language
|
var glyph: Glyph? = super.getGlyph(ch)
|
||||||
val fontForLanguage = "Nativefont"
|
if (glyph == null) {
|
||||||
val isUniqueFont = language.contains("Chinese") || language == "Korean" || language == "Japanese"
|
val charPixmap = fontImplementation.getCharPixmap(ch)
|
||||||
val keyForFont = if (!isUniqueFont) "$fontForLanguage $size" else "$fontForLanguage $size $language"
|
|
||||||
if (fontCache.containsKey(keyForFont)) return fontCache[keyForFont]!!
|
|
||||||
|
|
||||||
val font = NativeFont(NativeFontPaint(size))
|
glyph = Glyph()
|
||||||
val charsForFont = getCharactersForFont(if (isUniqueFont) language else "")
|
glyph.id = ch.toInt()
|
||||||
|
glyph.width = charPixmap.width
|
||||||
|
glyph.height = charPixmap.height
|
||||||
|
glyph.xadvance = glyph.width
|
||||||
|
|
||||||
|
val rect = packer.pack(charPixmap)
|
||||||
|
charPixmap.dispose()
|
||||||
|
glyph.page = packer.pages.size - 1 // Glyph is always packed into the last page for now.
|
||||||
|
glyph.srcX = rect.x.toInt()
|
||||||
|
glyph.srcY = rect.y.toInt()
|
||||||
|
|
||||||
font.appendText(charsForFont)
|
// If a page was added, create a new texture region for the incrementally added glyph.
|
||||||
|
if (regions.size <= glyph.page)
|
||||||
|
packer.updateTextureRegions(regions, filter, filter, false)
|
||||||
|
|
||||||
|
setGlyphRegion(glyph, regions.get(glyph.page))
|
||||||
|
setGlyph(ch.toInt(), glyph)
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
|
return glyph
|
||||||
|
}
|
||||||
|
|
||||||
fontCache[keyForFont] = font
|
override fun getGlyphs(run: GlyphLayout.GlyphRun, str: CharSequence, start: Int, end: Int, lastGlyph: Glyph?) {
|
||||||
return font
|
packer.packToTexture = true // All glyphs added after this are packed directly to the texture.
|
||||||
|
super.getGlyphs(run, str, start, end, lastGlyph)
|
||||||
|
if (dirty) {
|
||||||
|
dirty = false
|
||||||
|
packer.updateTextureRegions(regions, filter, filter, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
packer.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Fonts {
|
||||||
|
val font by lazy {
|
||||||
|
val fontData = NativeBitmapFontData(UncivGame.Current.fontImplementation!!)
|
||||||
|
val font = BitmapFont(fontData, fontData.regions, false)
|
||||||
|
font.setOwnsTexture(true)
|
||||||
|
font
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
package com.unciv.ui.worldscreen.mainmenu
|
package com.unciv.ui.worldscreen.mainmenu
|
||||||
|
|
||||||
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
|
||||||
import com.badlogic.gdx.Application
|
import com.badlogic.gdx.Application
|
||||||
import com.badlogic.gdx.Gdx
|
import com.badlogic.gdx.Gdx
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.*
|
import com.badlogic.gdx.scenes.scene2d.ui.*
|
||||||
import com.badlogic.gdx.utils.Array
|
import com.badlogic.gdx.utils.Array
|
||||||
import com.unciv.UncivGame
|
|
||||||
import com.unciv.logic.civilization.PlayerType
|
import com.unciv.logic.civilization.PlayerType
|
||||||
import com.unciv.models.UncivSound
|
import com.unciv.models.UncivSound
|
||||||
import com.unciv.models.translations.TranslationFileWriter
|
import com.unciv.models.translations.TranslationFileWriter
|
||||||
@ -16,6 +14,7 @@ import com.unciv.ui.utils.*
|
|||||||
import com.unciv.ui.worldscreen.WorldScreen
|
import com.unciv.ui.worldscreen.WorldScreen
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||||
|
|
||||||
class Language(val language:String, val percentComplete:Int){
|
class Language(val language:String, val percentComplete:Int){
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
@ -339,7 +338,6 @@ class WorldScreenOptionsPopup(val worldScreen:WorldScreen) : Popup(worldScreen)
|
|||||||
private fun selectLanguage() {
|
private fun selectLanguage() {
|
||||||
settings.language = selectedLanguage
|
settings.language = selectedLanguage
|
||||||
worldScreen.game.translations.tryReadTranslationForCurrentLanguage()
|
worldScreen.game.translations.tryReadTranslationForCurrentLanguage()
|
||||||
CameraStageBaseScreen.resetFonts() // to load chinese characters if necessary
|
|
||||||
reloadWorldAndOptions()
|
reloadWorldAndOptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,277 +0,0 @@
|
|||||||
package core.java.nativefont
|
|
||||||
|
|
||||||
import com.badlogic.gdx.Application
|
|
||||||
import com.badlogic.gdx.Gdx
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
|
||||||
import com.badlogic.gdx.graphics.Pixmap
|
|
||||||
import com.badlogic.gdx.graphics.Texture.TextureFilter
|
|
||||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
|
||||||
import com.badlogic.gdx.graphics.g2d.PixmapPacker
|
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
|
||||||
import com.badlogic.gdx.utils.Array
|
|
||||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by tian on 2016/10/2.
|
|
||||||
*/
|
|
||||||
class NativeFont @JvmOverloads constructor(paint: NativeFontPaint = NativeFontPaint()) : BitmapFont(BitmapFontData(), TextureRegion(), false) {
|
|
||||||
private var charSet: MutableSet<String?>?
|
|
||||||
private val emojiSet: HashMap<String?, EmojiDate?>
|
|
||||||
private val magFilter: TextureFilter
|
|
||||||
private val minFilter: TextureFilter
|
|
||||||
private var packer: PixmapPacker?
|
|
||||||
private var pageWidth = 512
|
|
||||||
private var paint: NativeFontPaint?
|
|
||||||
private var size = 0
|
|
||||||
|
|
||||||
inner class EmojiDate(var path: String, var size: Int)
|
|
||||||
|
|
||||||
private fun createListener() {
|
|
||||||
var className = "core.java.nativefont.NativeFont"
|
|
||||||
when (Gdx.app.type) {
|
|
||||||
Application.ApplicationType.Desktop -> {
|
|
||||||
className += "Desktop"
|
|
||||||
}
|
|
||||||
Application.ApplicationType.Android -> {
|
|
||||||
className += "Android"
|
|
||||||
}
|
|
||||||
Application.ApplicationType.iOS -> {
|
|
||||||
className += if (robovm) "IOS" else "IOSMoe"
|
|
||||||
}
|
|
||||||
Application.ApplicationType.WebGL -> {
|
|
||||||
className += "Html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
listener = try {
|
|
||||||
val claz = Gdx.app.javaClass.classLoader.loadClass(className) as Class<out NativeFontListener>
|
|
||||||
claz.newInstance()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
throw GdxRuntimeException("Class Not Found:" + e.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updataSize(newSize: Int) {
|
|
||||||
size = Math.max(newSize, size)
|
|
||||||
this.data.down = (-size).toFloat()
|
|
||||||
this.data.ascent = (-size).toFloat()
|
|
||||||
this.data.capHeight = size.toFloat()
|
|
||||||
this.data.lineHeight = size.toFloat()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setTextColor(color: Color?): NativeFont {
|
|
||||||
paint!!.color = color
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setStrokeColor(color: Color?): NativeFont {
|
|
||||||
paint!!.strokeColor = color
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setStrokeWidth(width: Int): NativeFont {
|
|
||||||
paint!!.strokeWidth = width
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSize(size: Int): NativeFont {
|
|
||||||
paint!!.textSize = size
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setBold(istrue: Boolean): NativeFont {
|
|
||||||
paint!!.fakeBoldText = istrue
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setUnderline(istrue: Boolean): NativeFont {
|
|
||||||
paint!!.underlineText = istrue
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setStrikeThru(istrue: Boolean): NativeFont {
|
|
||||||
paint!!.strikeThruText = istrue
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setPaint(paint: NativeFontPaint?): NativeFont {
|
|
||||||
this.paint = paint
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addEmojiPath(emojiKey: String?, imgPath: String, size: Int): NativeFont {
|
|
||||||
emojiSet[emojiKey] = EmojiDate(imgPath, size)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun appendEmoji(txt: String, imgname: String?, size: Int): NativeFont {
|
|
||||||
val pixmap = Pixmap(Gdx.files.internal(imgname))
|
|
||||||
// Pixmap.setFilter(Pixmap.Filter.BiLinear);
|
|
||||||
val pixmap2 = Pixmap(size, size, Pixmap.Format.RGBA8888)
|
|
||||||
pixmap2.filter = Pixmap.Filter.BiLinear
|
|
||||||
pixmap2.drawPixmap(pixmap, 0, 0, pixmap.width, pixmap.height, 0, 0, size, size)
|
|
||||||
pixmap.dispose()
|
|
||||||
appendEmoji(txt, pixmap2)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun appendEmoji(txt: String, pixmap: Pixmap): NativeFont {
|
|
||||||
if (charSet!!.add(txt)) {
|
|
||||||
if (packer == null) {
|
|
||||||
packer = PixmapPacker(pageWidth, pageWidth, Pixmap.Format.RGBA8888, 2, false)
|
|
||||||
}
|
|
||||||
putGlyph(txt[0], pixmap)
|
|
||||||
updataSize(pixmap.height)
|
|
||||||
upData()
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createText(characters: String?): NativeFont {
|
|
||||||
if (!(characters == null || characters.length == 0)) {
|
|
||||||
create(characters, true)
|
|
||||||
end()
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun appendText(characters: String?): NativeFont {
|
|
||||||
if (!(characters == null || characters.length == 0)) {
|
|
||||||
create(characters, false)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun create(characters: String, haveMinPageSize: Boolean) {
|
|
||||||
var characters = characters
|
|
||||||
characters = characters.replace("[\\t\\n\\x0B\\f\\r]".toRegex(), "")
|
|
||||||
val arrayOfCharsAsStrings = Array<String>()
|
|
||||||
for (c2 in characters.toCharArray()) {
|
|
||||||
if (charSet!!.add(c2.toString())) {
|
|
||||||
arrayOfCharsAsStrings.add(c2.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (haveMinPageSize) {
|
|
||||||
pageWidth = (paint!!.textSize + 2) * (Math.sqrt(arrayOfCharsAsStrings.size.toDouble()) + 1.0).toInt()
|
|
||||||
}
|
|
||||||
if (packer == null) {
|
|
||||||
packer = PixmapPacker(pageWidth, pageWidth, Pixmap.Format.RGBA8888, 2, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
val putGlyphStartTime = System.currentTimeMillis()
|
|
||||||
for (i in 0 until arrayOfCharsAsStrings.size) {
|
|
||||||
val txt = arrayOfCharsAsStrings[i]
|
|
||||||
val c2 = txt[0]
|
|
||||||
val css = c2.toString()
|
|
||||||
if (emojiSet[css] != null) {
|
|
||||||
charSet!!.remove(css)
|
|
||||||
val date = emojiSet[css]
|
|
||||||
appendEmoji(c2.toString() + "", date!!.path, date.size)
|
|
||||||
} else {
|
|
||||||
putGlyph(c2, listener!!.getFontPixmap(txt, paint!!))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val putGlyphTime = System.currentTimeMillis() - putGlyphStartTime
|
|
||||||
println("Putting glyphs - "+putGlyphTime+"ms")
|
|
||||||
|
|
||||||
updataSize(size)
|
|
||||||
upData()
|
|
||||||
|
|
||||||
if (regions.size == 1) {
|
|
||||||
setOwnsTexture(true)
|
|
||||||
} else {
|
|
||||||
setOwnsTexture(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun putGlyph(c: Char, pixmap: Pixmap) {
|
|
||||||
val rect = packer!!.pack(c.toString(), pixmap)
|
|
||||||
pixmap.dispose()
|
|
||||||
val pIndex = packer!!.getPageIndex(c.toString())
|
|
||||||
val glyph = Glyph()
|
|
||||||
glyph.id = c.toInt()
|
|
||||||
glyph.page = pIndex
|
|
||||||
glyph.srcX = rect.x.toInt()
|
|
||||||
glyph.srcY = rect.y.toInt()
|
|
||||||
glyph.width = rect.width.toInt()
|
|
||||||
glyph.height = rect.height.toInt()
|
|
||||||
glyph.xadvance = glyph.width
|
|
||||||
this.data!!.setGlyph(c.toInt(), glyph)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun upData() {
|
|
||||||
var spaceGlyph = this.data!!.getGlyph(' ')
|
|
||||||
if (spaceGlyph == null) {
|
|
||||||
spaceGlyph = Glyph()
|
|
||||||
var xadvanceGlyph = this.data!!.getGlyph('l')
|
|
||||||
if (xadvanceGlyph == null) {
|
|
||||||
xadvanceGlyph = this.data!!.firstGlyph
|
|
||||||
}
|
|
||||||
spaceGlyph.xadvance = xadvanceGlyph!!.xadvance
|
|
||||||
spaceGlyph.id = 32
|
|
||||||
this.data!!.setGlyph(32, spaceGlyph)
|
|
||||||
}
|
|
||||||
this.data!!.spaceXadvance = (spaceGlyph.xadvance + spaceGlyph.width).toFloat()
|
|
||||||
val pages = packer!!.pages
|
|
||||||
val regions = regions
|
|
||||||
val regSize = regions.size - 1
|
|
||||||
for (i in 0 until pages.size) {
|
|
||||||
val p = pages[i]
|
|
||||||
if (i > regSize) {
|
|
||||||
p.updateTexture(minFilter, magFilter, false)
|
|
||||||
regions.add(TextureRegion(p.texture))
|
|
||||||
} else {
|
|
||||||
if (p.updateTexture(minFilter, magFilter, false)) {
|
|
||||||
regions[i] = TextureRegion(p.texture)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (page in this.data!!.glyphs) {
|
|
||||||
if (page == null) continue
|
|
||||||
for (glyph in page) {
|
|
||||||
if (glyph != null) {
|
|
||||||
val region = getRegions()[glyph.page]
|
|
||||||
?: throw IllegalArgumentException("BitmapFont texture region array cannot contain null elements.")
|
|
||||||
this.data!!.setGlyphRegion(glyph, region)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun end(): NativeFont {
|
|
||||||
paint = null
|
|
||||||
charSet!!.clear()
|
|
||||||
charSet = null
|
|
||||||
packer!!.dispose()
|
|
||||||
packer = null
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dispose() {
|
|
||||||
end()
|
|
||||||
super.dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
var listener: NativeFontListener? = null
|
|
||||||
private set
|
|
||||||
private var robovm = false
|
|
||||||
fun setRobovm() {
|
|
||||||
robovm = true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.paint = NativeFontPaint()
|
|
||||||
charSet = HashSet()
|
|
||||||
packer = null
|
|
||||||
minFilter = TextureFilter.Linear
|
|
||||||
magFilter = TextureFilter.Linear
|
|
||||||
emojiSet = HashMap()
|
|
||||||
updataSize(paint.textSize)
|
|
||||||
if (listener == null) createListener()
|
|
||||||
this.paint = paint
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package core.java.nativefont
|
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Pixmap
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by tian on 2016/10/2.
|
|
||||||
*/
|
|
||||||
interface NativeFontListener {
|
|
||||||
fun getFontPixmap(txt: String, vpaint: NativeFontPaint): Pixmap
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
package core.java.nativefont
|
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by tian on 2016/10/2.
|
|
||||||
*/
|
|
||||||
class NativeFontPaint {
|
|
||||||
var textSize = 30 // 字号
|
|
||||||
var color = Color.WHITE // 颜色
|
|
||||||
var fakeBoldText = false // 是否粗体
|
|
||||||
var underlineText = false // 是否下划线
|
|
||||||
var strikeThruText = false // 是否删除线
|
|
||||||
var strokeColor: Color? = null // 描边颜色
|
|
||||||
var strokeWidth = 3 // 描边宽度
|
|
||||||
var tTFName = ""
|
|
||||||
val name: String
|
|
||||||
get() {
|
|
||||||
val name = StringBuffer()
|
|
||||||
name.append(tTFName).append("_").append(textSize).append("_").append(color.toIntBits())
|
|
||||||
.append("_").append(booleanToInt(fakeBoldText)).append("_")
|
|
||||||
.append(booleanToInt(underlineText))
|
|
||||||
if (strokeColor != null) {
|
|
||||||
name.append("_").append(strokeColor!!.toIntBits()).append("_").append(strokeWidth)
|
|
||||||
}
|
|
||||||
return name.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun booleanToInt(b: Boolean): Int {
|
|
||||||
return if (b == true) 0 else 1
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {}
|
|
||||||
constructor(ttfName: String, textSize: Int, color: Color, stroke: Color?, strokeWidth: Int,
|
|
||||||
bold: Boolean, line: Boolean, thru: Boolean) {
|
|
||||||
tTFName = ttfName
|
|
||||||
this.textSize = textSize
|
|
||||||
this.color = color
|
|
||||||
strokeColor = stroke
|
|
||||||
this.strokeWidth = strokeWidth
|
|
||||||
fakeBoldText = bold
|
|
||||||
underlineText = line
|
|
||||||
strikeThruText = thru
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(ttfName: String) {
|
|
||||||
tTFName = ttfName
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(ttfName: String, size: Int) {
|
|
||||||
tTFName = ttfName
|
|
||||||
textSize = size
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(ttfName: String, size: Int, color: Color) {
|
|
||||||
tTFName = ttfName
|
|
||||||
textSize = size
|
|
||||||
this.color = color
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(ttfName: String, color: Color) {
|
|
||||||
tTFName = ttfName
|
|
||||||
this.color = color
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(size: Int) {
|
|
||||||
textSize = size
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(color: Color) {
|
|
||||||
this.color = color
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(size: Int, color: Color) {
|
|
||||||
textSize = size
|
|
||||||
this.color = color
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -15,7 +15,6 @@ import java.util.*
|
|||||||
import kotlin.concurrent.timer
|
import kotlin.concurrent.timer
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
internal object DesktopLauncher {
|
internal object DesktopLauncher {
|
||||||
private var discordTimer: Timer? = null
|
private var discordTimer: Timer? = null
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ internal object DesktopLauncher {
|
|||||||
|
|
||||||
val versionFromJar = DesktopLauncher.javaClass.`package`.specificationVersion ?: "Desktop"
|
val versionFromJar = DesktopLauncher.javaClass.`package`.specificationVersion ?: "Desktop"
|
||||||
|
|
||||||
val game = UncivGame ( versionFromJar, null, { exitProcess(0) }, { discordTimer?.cancel() } )
|
val game = UncivGame ( versionFromJar, null, { exitProcess(0) }, { discordTimer?.cancel() }, NativeFontDesktop(45) )
|
||||||
|
|
||||||
if(!RaspberryPiDetector.isRaspberryPi()) // No discord RPC for Raspberry Pi, see https://github.com/yairm210/Unciv/issues/1624
|
if(!RaspberryPiDetector.isRaspberryPi()) // No discord RPC for Raspberry Pi, see https://github.com/yairm210/Unciv/issues/1624
|
||||||
tryActivateDiscord(game)
|
tryActivateDiscord(game)
|
||||||
|
47
desktop/src/com/unciv/app/desktop/NativeFontDesktop.kt
Executable file
47
desktop/src/com/unciv/app/desktop/NativeFontDesktop.kt
Executable file
@ -0,0 +1,47 @@
|
|||||||
|
package com.unciv.app.desktop
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
|
import com.unciv.ui.utils.NativeFontImplementation
|
||||||
|
import java.awt.*
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
|
||||||
|
|
||||||
|
class NativeFontDesktop(val size: Int) : NativeFontImplementation {
|
||||||
|
private val font by lazy {
|
||||||
|
Font("", Font.PLAIN, size)
|
||||||
|
}
|
||||||
|
private val metric by lazy {
|
||||||
|
val bi = BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR)
|
||||||
|
val g = bi.createGraphics()
|
||||||
|
g.font = font
|
||||||
|
g.fontMetrics!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFontSize(): Int {
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCharPixmap(char: Char): Pixmap {
|
||||||
|
var width = metric.charWidth(char)
|
||||||
|
var height = metric.ascent + metric.descent
|
||||||
|
if (width == 0) {
|
||||||
|
height = size
|
||||||
|
width = height
|
||||||
|
}
|
||||||
|
val bi = BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR)
|
||||||
|
val g = bi.createGraphics()
|
||||||
|
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g.font = font
|
||||||
|
g.color = Color.WHITE
|
||||||
|
g.drawString(char.toString(), 0, metric.ascent)
|
||||||
|
val pixmap = Pixmap(bi.width, bi.height, Pixmap.Format.RGBA8888)
|
||||||
|
val data = bi.getRGB(0, 0, bi.width, bi.height, null, 0, bi.width)
|
||||||
|
for (i in 0 until bi.width) {
|
||||||
|
for (j in 0 until bi.height) {
|
||||||
|
pixmap.setColor(Integer.reverseBytes(data[i + (j * bi.width)]))
|
||||||
|
pixmap.drawPixel(i, j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pixmap
|
||||||
|
}
|
||||||
|
}
|
@ -1,104 +0,0 @@
|
|||||||
package core.java.nativefont
|
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx
|
|
||||||
import com.badlogic.gdx.graphics.Pixmap
|
|
||||||
import java.awt.*
|
|
||||||
import java.awt.font.TextAttribute
|
|
||||||
import java.awt.image.BufferedImage
|
|
||||||
import java.io.BufferedInputStream
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.io.IOException
|
|
||||||
import java.text.AttributedString
|
|
||||||
import java.util.*
|
|
||||||
import javax.imageio.ImageIO
|
|
||||||
import javax.swing.UIManager
|
|
||||||
|
|
||||||
class NativeFontDesktop : NativeFontListener {
|
|
||||||
private val fonts = HashMap<String, Font?>()
|
|
||||||
private val metrics = HashMap<String, FontMetrics>()
|
|
||||||
override fun getFontPixmap(txt: String, vpaint: NativeFontPaint): Pixmap {
|
|
||||||
val font = getFont(vpaint)
|
|
||||||
val fm = metrics[vpaint.name]
|
|
||||||
var strWidth = fm!!.stringWidth(txt)
|
|
||||||
var strHeight = fm.ascent + fm.descent
|
|
||||||
if (strWidth == 0) {
|
|
||||||
strHeight = vpaint.textSize
|
|
||||||
strWidth = strHeight
|
|
||||||
}
|
|
||||||
val bi = BufferedImage(strWidth, strHeight, BufferedImage.TYPE_4BYTE_ABGR)
|
|
||||||
val g = bi.createGraphics()
|
|
||||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
|
||||||
g.font = font
|
|
||||||
when {
|
|
||||||
vpaint.strokeColor != null -> { // 描边
|
|
||||||
val v = font!!.createGlyphVector(fm.fontRenderContext, txt)
|
|
||||||
val shape = v.outline
|
|
||||||
g.color = UIManager.getColor(vpaint.color)
|
|
||||||
g.translate(0, fm.ascent)
|
|
||||||
g.fill(shape)
|
|
||||||
g.stroke = BasicStroke(vpaint.strokeWidth.toFloat())
|
|
||||||
g.color = UIManager.getColor(vpaint.strokeColor)
|
|
||||||
g.draw(shape)
|
|
||||||
}
|
|
||||||
vpaint.underlineText -> { // 下划线
|
|
||||||
val `as` = AttributedString(txt)
|
|
||||||
`as`.addAttribute(TextAttribute.FONT, font)
|
|
||||||
`as`.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON)
|
|
||||||
g.color = UIManager.getColor(vpaint.color)
|
|
||||||
g.drawString(`as`.iterator, 0, fm.ascent)
|
|
||||||
}
|
|
||||||
vpaint.strikeThruText -> { // 删除线
|
|
||||||
val `as` = AttributedString(txt)
|
|
||||||
`as`.addAttribute(TextAttribute.FONT, font)
|
|
||||||
`as`.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON)
|
|
||||||
g.color = UIManager.getColor(vpaint.color)
|
|
||||||
g.drawString(`as`.iterator, 0, fm.ascent)
|
|
||||||
}
|
|
||||||
else -> { // 普通
|
|
||||||
g.color = UIManager.getColor(vpaint.color)
|
|
||||||
g.drawString(txt, 0, fm.ascent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lateinit var pixmap: Pixmap
|
|
||||||
try {
|
|
||||||
val buffer = ByteArrayOutputStream()
|
|
||||||
ImageIO.write(bi, "png", buffer)
|
|
||||||
pixmap = Pixmap(buffer.toByteArray(), 0, buffer.toByteArray().size)
|
|
||||||
buffer.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
return pixmap
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getFont(vpaint: NativeFontPaint): Font? {
|
|
||||||
val isBolo = vpaint.fakeBoldText || vpaint.strokeColor != null
|
|
||||||
var font = fonts[vpaint.name]
|
|
||||||
if (font == null) {
|
|
||||||
if (vpaint.tTFName == "") {
|
|
||||||
font = Font("", if (isBolo) Font.BOLD else Font.PLAIN, vpaint.textSize)
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
val `in` = ByteArrayInputStream(Gdx.files.internal(vpaint.tTFName +
|
|
||||||
if (vpaint.tTFName.endsWith(".ttf")) "" else ".ttf").readBytes())
|
|
||||||
val fb = BufferedInputStream(`in`)
|
|
||||||
font = Font.createFont(Font.TRUETYPE_FONT, fb).deriveFont(Font.BOLD, vpaint.textSize.toFloat())
|
|
||||||
fb.close()
|
|
||||||
`in`.close()
|
|
||||||
} catch (e: FontFormatException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fonts[vpaint.name] = font
|
|
||||||
val bi = BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR)
|
|
||||||
val g = bi.createGraphics()
|
|
||||||
g.font = font
|
|
||||||
val fm = g.fontMetrics
|
|
||||||
metrics[vpaint.name] = fm
|
|
||||||
}
|
|
||||||
return font
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user