can use native font and "WenQuanYimicroHei" in andriod and desktop (#1013)

* Update Other.json

* Update Notifications.json

* Update Other.json

* Can Change Language With No "ttf" Font

* update

* Update AndroidLauncher.java

* repair app running slowly in using no "tff" class

* Can Change Language with No "ttf" Font (#772)

* Update Other.json

* Update Notifications.json

* Update Other.json

* Can Change Language With No "ttf" Font

* update

* Update AndroidLauncher.java

* repair app running slowly in using no "tff" class

* update nativefont for Desktop and IOS

* Delete NativeFontIOS.java

* can choose nativefont or font downloading from internet

* update

* update

* Update Fonts.kt

* Update Fonts.kt

* update

* update

* update

* update

* Update build.gradle

* update

* update

* update

* can choose native font or "WenquanYiMicroHei"

* update

* update

* update

* update
This commit is contained in:
lishaoxia1985 2019-09-01 18:01:37 +08:00 committed by Yair Morgenstern
parent 8d3a2d6da3
commit 62a85cd14a
14 changed files with 807 additions and 239 deletions

Binary file not shown.

View file

@ -1,94 +0,0 @@
Copyright (c) 2011, Ang<6E>lica D<>iaz (http://typereview.wordpress.com|angiecina@gmail.com),
with Reserved Font Name "Esteban"
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View file

@ -0,0 +1,78 @@
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.HashMap;
/**
* Created by tian on 2016/10/2.
*/
public class NativeFontAndroid implements NativeFontListener {
private HashMap<String, Typeface> fontFaces = new HashMap<String, Typeface>();
private AndroidApplication androidApplication = (AndroidApplication) Gdx.app;
@Override
public Pixmap getFontPixmap(String txt, NativeFontPaint vpaint) {
Paint paint = new Paint();
if (!vpaint.getTTFName().equals("")) {
// Typeface fontFace = fontFaces.get(vpaint.getTTFName());
Gdx.app.log("app",Gdx.files.internal(vpaint.getTTFName()
+ (vpaint.getTTFName().endsWith(".ttf") ? ""
: ".ttf")).file().getPath());
Typeface fontFace = Typeface.createFromAsset(androidApplication.getAssets(),vpaint.getTTFName()
+ (vpaint.getTTFName().endsWith(".ttf") ? ""
: ".ttf"));
fontFaces.put(vpaint.getTTFName(), fontFace);
paint.setTypeface(fontFace);
}
paint.setAntiAlias(true);
paint.setTextSize(vpaint.getTextSize());
Paint.FontMetrics fm = paint.getFontMetrics();
int w = (int) paint.measureText(txt);
int h = (int) (fm.descent - fm.ascent);
if (w == 0) {
w = h = vpaint.getTextSize();
}
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
// 如果是描边类型
if (vpaint.getStrokeColor() != null) {
// 绘制外层
paint.setColor(getColor(vpaint.getStrokeColor()));
paint.setStrokeWidth(vpaint.getStrokeWidth()); // 描边宽度
paint.setStyle(Paint.Style.FILL_AND_STROKE); // 描边种类
paint.setFakeBoldText(true); // 外层text采用粗体
canvas.drawText(txt, 0, -fm.ascent, paint);
paint.setFakeBoldText(false);
} else {
paint.setUnderlineText(vpaint.getUnderlineText());
paint.setStrikeThruText(vpaint.getStrikeThruText());
paint.setFakeBoldText(vpaint.getFakeBoldText());
}
// 绘制内层
paint.setStrokeWidth(0);
paint.setColor(getColor(vpaint.getColor()));
canvas.drawText(txt, 0, -fm.ascent, paint);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, buffer);
byte[] encodedData = buffer.toByteArray();
Pixmap pixmap = new Pixmap(encodedData, 0, encodedData.length);
bitmap = null;
canvas = null;
return pixmap;
}
private int getColor(Color color) {
return (((((int) (color.a * 255.0f)) << 24) | (((int) (color.r * 255.0f)) << 16)) | (((int) (color.g * 255.0f)) << 8)) | ((int) (color.b * 255.0f));
}
}

View file

@ -7,6 +7,7 @@ class GameSettings {
var showResourcesAndImprovements: Boolean = true
var checkForDueUnits: Boolean = true
var singleTapMove: Boolean = false
var fontSet:String = "NativeFont(Recommended)"
var language: String = "English"
var resolution: String = "1050x700"
var tutorialsShown = ArrayList<String>()

View file

@ -1,6 +1,5 @@
package com.unciv.ui
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Label
@ -11,8 +10,6 @@ import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tr
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.optionstable.PopupTable
import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable
class LanguageTable(val language:String,skin: Skin):Table(skin){
@ -77,24 +74,7 @@ class LanguagePickerScreen: PickerScreen(){
rightSideButton.onClick {
if (Fonts().containsFont(Fonts().getFontForLanguage(chosenLanguage)))
pickLanguage()
else {
val spaceSplitLang = chosenLanguage.replace("_"," ")
YesNoPopupTable("This language requires you to download fonts.\n" +
"Do you want to download fonts for $spaceSplitLang?",
{
val downloading = PopupTable(this)
downloading.add("Downloading...".toLabel())
downloading.open()
Gdx.input.inputProcessor = null // no interaction until download is over
kotlin.concurrent.thread {
Fonts().downloadFontForLanguage(chosenLanguage)
shouldPickLanguage = true
}
},this)
}
pickLanguage()
}
}
@ -105,12 +85,4 @@ class LanguagePickerScreen: PickerScreen(){
UnCivGame.Current.startNewGame()
dispose()
}
var shouldPickLanguage=false
override fun render(delta: Float) {
if(shouldPickLanguage)
pickLanguage()
super.render(delta)
}
}

View file

@ -1,40 +1,68 @@
package com.unciv.ui.utils
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator
import com.unciv.UnCivGame
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tr
import com.unciv.ui.worldscreen.optionstable.PopupTable
import core.java.nativefont.NativeFont
import core.java.nativefont.NativeFontPaint
import java.io.FileOutputStream
import java.io.FileInputStream
import java.net.URL
import java.security.*
class Fonts {
companion object {
// Contains e.g. "Arial 22", fontname and size, to BitmapFont
val fontCache = HashMap<String, BitmapFont>()
}
fun getFontForLanguage(language:String): String {
if (language.contains("Chinese")) return chineseFont
else return "Arial"
fun download(link: String,fontForLanguage: String) {
if (!Gdx.files.local("fonts").exists())
Gdx.files.local("fonts").mkdirs()
val input = URL(link).openStream()
val output = FileOutputStream(Gdx.files.local("fonts/$fontForLanguage.ttf").file())
input.use {
output.use {
input.copyTo(output)
}
}
}
val chineseFont = "WenQuanYiMicroHei"
fun getCharsForFont(font: String): String {
fun getMD5(fontForLanguage: String):String {
val sb = StringBuffer("")
val md = MessageDigest.getInstance("MD5")
if (Gdx.files.local("fonts/$fontForLanguage.ttf").exists()) {
md.update(FileInputStream(Gdx.files.local("fonts/$fontForLanguage.ttf").file()).readBytes())
val b = md.digest()
for (i in b) {
var d = i.toInt()
if (d < 0) d = i + 256
if (d < 16) sb.append("0")
sb.append(Integer.toHexString(d))
}
return sb.toString()
}
return ""
}
fun containsFont(): Boolean {
if (Gdx.files.local("fonts/WenQuanYiMicroHei.ttf").exists())
return true
return false
}
fun getCharsForFont(): String {
val defaultText = "ABCČĆDĐEFGHIJKLMNOPQRSŠTUVWXYZŽaäàâăbcčćçdđeéfghiîjklmnoöpqrsșštțuüvwxyzž" +
"АБВГҐДЂЕЁЄЖЗЅИІЇЙЈКЛЉМНЊОПРСТЋУЎФХЦЧЏШЩЪЫЬЭЮЯабвгґдђеёєжзѕиіїйјклљмнњопрстћуўфхцчџшщъыьэюя" +
"ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωάßΆέΈέΉίϊΐΊόΌύΰϋΎΫΏ" +
"ÀÄĂÂĎÊĚÉÈÍÎŁĹĽÔÓÖƠŘŔŚŤƯŮÚÜŻŹäâąďêęěłĺľńňôöơřŕśťưůýżźáèìíóú1234567890" +
"?'“!”(%)[#]{@}/&\\<-+÷×=>®©\$€£¥¢:;,.¡*|"
if (font == "Arial") return defaultText
if (font == chineseFont) {
val charSet = HashSet<Char>()
charSet.addAll(defaultText.asIterable())
if(Gdx.files.internal("BasicHelp/BasicHelp_Simplified_Chinese.json").exists())
charSet.addAll(Gdx.files.internal("BasicHelp/BasicHelp_Simplified_Chinese.json").readString().asIterable())
if(Gdx.files.internal("jsons/BasicHelp/BasicHelp_Simplified_Chinese.json").exists())
charSet.addAll(Gdx.files.internal("jsons/BasicHelp/BasicHelp_Simplified_Chinese.json").readString().asIterable())
if (Gdx.files.internal("jsons/Nations_Simplified_Chinese.json").exists())
charSet.addAll(Gdx.files.internal("jsons/Nations_Simplified_Chinese.json").readString().asIterable())
if (Gdx.files.internal("jsons/Tutorials/Tutorials_Simplified_Chinese.json").exists())
@ -46,66 +74,41 @@ class Fonts {
}
}
return charSet.joinToString()
}
return ""
}
fun download(link: String, path: String) {
val input = URL(link).openStream()
val output = FileOutputStream(Gdx.files.local(path).file())
input.use {
output.use {
input.copyTo(output)
}
}
}
fun containsFont(font:String): Boolean {
if (Gdx.files.internal("skin/$font.ttf").exists())
return true
if (Gdx.files.local("fonts/$font.ttf").exists())
return true
return false
}
fun downloadFontForLanguage(language:String){
val font = getFontForLanguage(language)
if(containsFont(language)) return
if (!Gdx.files.local("fonts").exists())
Gdx.files.local("fonts").mkdirs()
val localPath = "fonts/$font.ttf"
if (font == chineseFont)
download("https://github.com/layerssss/wqy/raw/gh-pages/fonts/WenQuanYiMicroHei.ttf", localPath)//This font is licensed under Apache2.0 or GPLv3
}
fun getFont(size: Int): BitmapFont {
val language = UnCivGame.Current.settings.language
val fontForLanguage = getFontForLanguage(language)
val keyForFont = "$fontForLanguage $size"
if (fontCache.containsKey(keyForFont)) return fontCache[keyForFont]!!
val generator: FreeTypeFontGenerator
if (Gdx.files.internal("skin/$fontForLanguage.ttf").exists())
generator = FreeTypeFontGenerator(Gdx.files.internal("skin/$fontForLanguage.ttf"))
else {
val localPath = "fonts/$fontForLanguage.ttf"
if(!containsFont(fontForLanguage)) downloadFontForLanguage(language)
generator = FreeTypeFontGenerator(Gdx.files.local(localPath))
}
val parameter = FreeTypeFontGenerator.FreeTypeFontParameter()
parameter.size = size
parameter.minFilter = Texture.TextureFilter.Linear
parameter.magFilter = Texture.TextureFilter.Linear
parameter.characters = getCharsForFont(fontForLanguage)
val font = generator.generateFont(parameter)
generator.dispose() // don't forget to dispose to avoid memory leaks!
fontCache[keyForFont] = font
return font
}
fun getFont(size: Int): BitmapFont {
if(UnCivGame.Current.settings.fontSet=="WenQuanYiMicroHei"){
val fontForLanguage="WenQuanYiMicroHei"
val keyForFont = "$fontForLanguage $size"
if (fontCache.containsKey(keyForFont))
return fontCache[keyForFont]!!
if (getMD5(fontForLanguage)!="96574d6f2f2bbd4a3ce56979623b1952"){
Gdx.files.local("fonts/$fontForLanguage.ttf").delete()
UnCivGame.Current.settings.fontSet="NativeFont(Recommended)"
Gdx.app.postRunnable {
val downloading = PopupTable(UnCivGame.Current.worldScreen)
downloading.add("Checksum error!\nIf you want to use the font \"WenQuanYiMicroHei\", please download again.".toLabel().setFontColor(Color.RED)).row()
downloading.addButton("Close".tr()) { downloading.remove() }.row()
downloading.open()
}
}
else {
val generator = FreeTypeFontGenerator(Gdx.files.local("fonts/WenQuanYiMicroHei.ttf"))
val parameter = FreeTypeFontGenerator.FreeTypeFontParameter()
parameter.size = size
parameter.minFilter = Texture.TextureFilter.Linear
parameter.magFilter = Texture.TextureFilter.Linear
parameter.characters = getCharsForFont()
val font = generator.generateFont(parameter)
fontCache[keyForFont] = font
return font
}
}
val fontForLanguage ="Nativefont"
val keyForFont = "$fontForLanguage $size"
if (fontCache.containsKey(keyForFont))return fontCache[keyForFont]!!
val font=NativeFont(NativeFontPaint(size))
font.appendText(getCharsForFont())
fontCache[keyForFont] = font
return font
}
}

View file

@ -1,7 +1,7 @@
package com.unciv.ui.worldscreen.optionstable
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.g2d.Batch
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.ui.*
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener
@ -11,6 +11,7 @@ import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tr
import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.WorldScreen
import java.io.IOException
import kotlin.concurrent.thread
class Language(val language:String){
@ -76,6 +77,8 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr
update()
}
addFontSelectBox(innerTable)
addLanguageSelectBox(innerTable)
addResolutionSelectBox(innerTable)
@ -196,6 +199,62 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr
})
}
private fun addFontSelectBox(innerTable: PopupTable) {
innerTable.add("Fontset".toLabel())
val FontSetSelectBox = SelectBox<String>(skin)
val FontSetArray = Array<String>()
FontSetArray.add("NativeFont(Recommended)")
FontSetArray.add("WenQuanYiMicroHei")
FontSetSelectBox.items = FontSetArray
FontSetSelectBox.selected = UnCivGame.Current.settings.fontSet
innerTable.add(FontSetSelectBox).pad(10f).row()
FontSetSelectBox.addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
UnCivGame.Current.settings.fontSet = FontSetSelectBox.selected
if (FontSetSelectBox.selected == "NativeFont(Recommended)"||Fonts().containsFont()) {
selectFont()
}
else {
YesNoPopupTable("This Font requires you to download fonts.\n" +
"Do you want to download fonts(about 4.2MB)?",
{
val downloading = PopupTable(screen)
downloading.add("Downloading...\n".toLabel()).row()
downloading.add("Warning:Don't switch this game to background until download finished.".toLabel().setFontColor(Color.RED)).row()
downloading.open()
Gdx.input.inputProcessor = null
thread {
try {
Fonts().download("https://github.com/layerssss/wqy/raw/gh-pages/fonts/WenQuanYiMicroHei.ttf", "WenQuanYiMicroHei")//This font is licensed under Apache2.0 or GPLv3
Gdx.app.postRunnable {
selectFont()
}
}
catch (e: IOException) {
Gdx.app.postRunnable {
FontSetSelectBox.selected = "NativeFont(Recommended)"
val downloading = PopupTable(UnCivGame.Current.worldScreen)
downloading.add("Download failed!\nPlease check your internet connection.".toLabel().setFontColor(Color.RED)).row()
downloading.addButton("Close".tr()) { downloading.remove() }.row()
downloading.open()
}
}
}
}, UnCivGame.Current.worldScreen, {FontSetSelectBox.selected = "NativeFont(Recommended)"})
}
}
})
}
fun selectFont(){
UnCivGame.Current.settings.save()
CameraStageBaseScreen.resetFonts()
UnCivGame.Current.worldScreen = WorldScreen(worldScreen.viewingCiv)
UnCivGame.Current.setWorldScreen()
WorldScreenOptionsTable(UnCivGame.Current.worldScreen)
}
private fun addLanguageSelectBox(innerTable: PopupTable) {
innerTable.add("Language".toLabel())
val languageSelectBox = SelectBox<Language>(skin)
@ -209,27 +268,7 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr
languageSelectBox.addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
selectedLanguage = languageSelectBox.selected.language
if (Fonts().containsFont(Fonts().getFontForLanguage(selectedLanguage)))
selectLanguage()
else {
val spaceSplitLang = selectedLanguage.replace("_", " ")
YesNoPopupTable("This language requires you to download fonts.\n" +
"Do you want to download fonts for $spaceSplitLang?",
{
val downloading = PopupTable(screen)
downloading.add("Downloading...".toLabel())
downloading.open()
Gdx.input.inputProcessor = null // no interaction until download is over
thread {
Fonts().downloadFontForLanguage(selectedLanguage)
// The language selection must be done on the render thread, because it requires a GL context.
// This means that we have to tell the table to create it on render.
shouldSelectLanguage = true
}
})
}
selectLanguage()
}
})
@ -245,25 +284,11 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr
}
}
fun selectLanguage(){
UnCivGame.Current.settings.language = selectedLanguage
UnCivGame.Current.settings.save()
CameraStageBaseScreen.resetFonts()
UnCivGame.Current.worldScreen = WorldScreen(worldScreen.viewingCiv)
UnCivGame.Current.setWorldScreen()
WorldScreenOptionsTable(UnCivGame.Current.worldScreen)
}
var shouldSelectLanguage = false
override fun draw(batch: Batch?, parentAlpha: Float) {
if(shouldSelectLanguage){
shouldSelectLanguage=false
selectLanguage()
}
super.draw(batch, parentAlpha)
}
}

View file

@ -8,12 +8,12 @@ import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.toLabel
class YesNoPopupTable(question:String, action:()->Unit,
screen: CameraStageBaseScreen = UnCivGame.Current.worldScreen) : PopupTable(screen){
screen: CameraStageBaseScreen = UnCivGame.Current.worldScreen, restoredefault:()->Unit = {}) : PopupTable(screen){
init{
if(!screen.hasPopupOpen) {
screen.hasPopupOpen=true
add(question.toLabel()).colspan(2).row()
add(TextButton("No".tr(), skin).onClick { close() })
add(TextButton("No".tr(), skin).onClick { close(); restoredefault() })
add(TextButton("Yes".tr(), skin).onClick { close(); action() })
open()
}

View file

@ -0,0 +1,299 @@
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;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.PixmapPacker;
import com.badlogic.gdx.graphics.g2d.PixmapPacker.Page;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
/**
* Created by tian on 2016/10/2.
*/
public class NativeFont extends BitmapFont {
private static NativeFontListener listener;
private static boolean robovm;
private Set<String> charSet;
private BitmapFontData data;
private HashMap<String, EmojiDate> emojiSet;
private Texture.TextureFilter magFilter;
private Texture.TextureFilter minFilter;
private PixmapPacker packer;
private int pageWidth;
private NativeFontPaint paint;
private int size;
public class EmojiDate {
public String path;
public int size;
public EmojiDate(String path, int size) {
this.path = path;
this.size = size;
}
}
public NativeFont() {
this(new NativeFontPaint());
}
public NativeFont(NativeFontPaint paint) {
super(new BitmapFontData(), new TextureRegion(), false);
this.pageWidth = 512;
this.paint = new NativeFontPaint();
this.charSet = new HashSet();
this.packer = null;
this.minFilter = Texture.TextureFilter.Linear;
this.magFilter = Texture.TextureFilter.Linear;
this.emojiSet = new HashMap();
updataSize(paint.getTextSize());
if (listener == null) createListener();
this.paint = paint;
}
private void createListener() {
String className = "core.java.nativefont.NativeFont";
if (Gdx.app.getType() == Application.ApplicationType.Desktop) {
className += "Desktop";
} else if (Gdx.app.getType() == Application.ApplicationType.Android) {
className += "Android";
} else if (Gdx.app.getType() == Application.ApplicationType.iOS) {
if (robovm)
className += "IOS";
else
className += "IOSMoe";
}else if (Gdx.app.getType() == Application.ApplicationType.WebGL){
className += "Html";
}
try {
Class<? extends NativeFontListener> claz = (Class<? extends NativeFontListener>) Gdx.app.getClass().getClassLoader().loadClass(className);
listener = claz.newInstance();
} catch (Exception e) {
throw new GdxRuntimeException("Class Not Found:" + e.getMessage());
}
}
public void updataSize(int newSize) {
this.data = getData();
this.size = Math.max(newSize, this.size);
this.data.down = (float) (-this.size);
this.data.ascent = (float) (-this.size);
this.data.capHeight = (float) this.size;
this.data.lineHeight = (float) this.size;
}
public NativeFont setTextColor(Color color) {
this.paint.setColor(color);
return this;
}
public NativeFont setStrokeColor(Color color) {
this.paint.setStrokeColor(color);
return this;
}
public NativeFont setStrokeWidth(int width) {
this.paint.setStrokeWidth(width);
return this;
}
public NativeFont setSize(int size) {
this.paint.setTextSize(size);
return this;
}
public NativeFont setBold(boolean istrue) {
this.paint.setFakeBoldText(istrue);
return this;
}
public NativeFont setUnderline(boolean istrue) {
this.paint.setUnderlineText(istrue);
return this;
}
public NativeFont setStrikeThru(boolean istrue) {
this.paint.setStrikeThruText(istrue);
return this;
}
public NativeFont setPaint(NativeFontPaint paint) {
this.paint = paint;
return this;
}
public NativeFont addEmojiPath(String emojiKey, String imgPath, int size) {
this.emojiSet.put(emojiKey, new EmojiDate(imgPath, size));
return this;
}
public NativeFont appendEmoji(String txt, String imgname, int size) {
Pixmap pixmap = new Pixmap(Gdx.files.internal(imgname));
// Pixmap.setFilter(Pixmap.Filter.BiLinear);
Pixmap pixmap2 = new Pixmap(size, size, Pixmap.Format.RGBA8888);
pixmap2.setFilter(Pixmap.Filter.BiLinear);
pixmap2.drawPixmap(pixmap, 0, 0, pixmap.getWidth(), pixmap.getHeight(), 0, 0, size, size);
pixmap.dispose();
appendEmoji(txt, pixmap2);
return this;
}
public NativeFont appendEmoji(String txt, Pixmap pixmap) {
if (this.charSet.add(txt)) {
if (this.packer == null) {
this.packer = new PixmapPacker(this.pageWidth, this.pageWidth, Pixmap.Format.RGBA8888, 2, false);
}
putGlyph(txt.charAt(0), pixmap);
updataSize(pixmap.getHeight());
upData();
}
return this;
}
public NativeFont createText(String characters) {
if (!(characters == null || characters.length() == 0)) {
create(characters, true);
end();
}
return this;
}
public NativeFont appendText(String characters) {
if (!(characters == null || characters.length() == 0)) {
create(characters, false);
}
return this;
}
private void create(String characters, boolean haveMinPageSize) {
char c;
characters = characters.replaceAll("[\\t\\n\\x0B\\f\\r]", "");
Array<String> cs = new Array<String>();
for (char c2 : characters.toCharArray()) {
if (this.charSet.add((String.valueOf(c2)))) {
cs.add((String.valueOf(c2)));
}
}
if (haveMinPageSize) {
this.pageWidth = (this.paint.getTextSize() + 2) * ((int) (Math.sqrt((double) cs.size) + 1.0d));
}
if (this.packer == null) {
this.packer = new PixmapPacker(this.pageWidth, this.pageWidth, Pixmap.Format.RGBA8888, 2, false);
}
char c2;
for (int i = 0; i < cs.size; i++) {
String txt = cs.get(i);
c2 = txt.charAt(0);
String css = String.valueOf(c2);
if (this.emojiSet.get(css) != null) {
this.charSet.remove(css);
EmojiDate date = this.emojiSet.get(css);
appendEmoji(c2 + "", date.path, date.size);
} else {
putGlyph(c2, this.listener.getFontPixmap(txt, this.paint));
}
}
updataSize(this.size);
upData();
if (getRegions().size == 1) {
setOwnsTexture(true);
} else {
setOwnsTexture(false);
}
}
private void putGlyph(char c, Pixmap pixmap) {
Rectangle rect = this.packer.pack(String.valueOf(c), pixmap);
pixmap.dispose();
int pIndex = this.packer.getPageIndex((String.valueOf(c)));
Glyph glyph = new Glyph();
glyph.id = c;
glyph.page = pIndex;
glyph.srcX = (int) rect.x;
glyph.srcY = (int) rect.y;
glyph.width = (int) rect.width;
glyph.height = (int) rect.height;
glyph.xadvance = glyph.width;
this.data.setGlyph(c, glyph);
}
private void upData() {
Glyph spaceGlyph = this.data.getGlyph(' ');
if (spaceGlyph == null) {
spaceGlyph = new Glyph();
Glyph xadvanceGlyph = this.data.getGlyph('l');
if (xadvanceGlyph == null) {
xadvanceGlyph = this.data.getFirstGlyph();
}
spaceGlyph.xadvance = xadvanceGlyph.xadvance;
spaceGlyph.id = 32;
this.data.setGlyph(32, spaceGlyph);
}
this.data.spaceXadvance = (float) (spaceGlyph.xadvance + spaceGlyph.width);
Array<Page> pages = this.packer.getPages();
Array<TextureRegion> regions = getRegions();
int regSize = regions.size - 1;
for (int i = 0; i < pages.size; i++) {
Page p = pages.get(i);
if (i > regSize) {
p.updateTexture(this.minFilter, this.magFilter, false);
regions.add(new TextureRegion(p.getTexture()));
} else {
if (p.updateTexture(this.minFilter, this.magFilter, false)) {
regions.set(i, new TextureRegion(p.getTexture()));
}
}
}
for (Glyph[] page : this.data.glyphs) {
if (page == null) continue;
for (Glyph glyph : page) {
if (glyph != null) {
TextureRegion region = (TextureRegion) getRegions().get(glyph.page);
if (region == null) {
throw new IllegalArgumentException("BitmapFont texture region array cannot contain null elements.");
}
this.data.setGlyphRegion(glyph, region);
}
}
}
}
public NativeFont end() {
this.paint = null;
this.charSet.clear();
this.charSet = null;
this.packer.dispose();
this.packer = null;
return this;
}
public void dispose() {
end();
super.dispose();
}
public static void setRobovm() {
robovm = true;
}
public static NativeFontListener getListener() {
return listener;
}
}

View file

@ -0,0 +1,11 @@
package core.java.nativefont;
import com.badlogic.gdx.graphics.Pixmap;
/**
* Created by tian on 2016/10/2.
*/
public interface NativeFontListener {
Pixmap getFontPixmap(String str, NativeFontPaint freePaint);
}

View file

@ -0,0 +1,146 @@
package core.java.nativefont;
import com.badlogic.gdx.graphics.Color;
/**
* Created by tian on 2016/10/2.
*/
public class NativeFontPaint {
private int textSize = 30;// 字号
private Color color = Color.WHITE;// 颜色
private boolean isFakeBoldText = false;// 是否粗体
private boolean isUnderlineText = false;// 是否下划线
private boolean isStrikeThruText = false;// 是否删除线
private Color strokeColor = null;// 描边颜色
private int strokeWidth = 3;// 描边宽度
private String ttfName = "";
public String getName() {
StringBuffer name = new StringBuffer();
name.append(ttfName).append("_").append(textSize).append("_").append(color.toIntBits())
.append("_").append(booleanToInt(isFakeBoldText)).append("_")
.append(booleanToInt(isUnderlineText));
if (strokeColor != null) {
name.append("_").append(strokeColor.toIntBits()).append("_").append(strokeWidth);
}
return name.toString();
}
private int booleanToInt(boolean b) {
return b == true ? 0 : 1;
}
public NativeFontPaint() {
}
public NativeFontPaint(String ttfName, int textSize, Color color, Color stroke, int strokeWidth,
boolean bold, boolean line, boolean thru) {
this.ttfName = ttfName;
this.textSize = textSize;
this.color = color;
this.strokeColor = stroke;
this.strokeWidth = strokeWidth;
this.isFakeBoldText = bold;
this.isUnderlineText = line;
this.isStrikeThruText = thru;
}
public NativeFontPaint(String ttfName) {
this.ttfName = ttfName;
}
public NativeFontPaint(String ttfName, int size) {
this.ttfName = ttfName;
this.textSize = size;
}
public NativeFontPaint(String ttfName, int size, Color color) {
this.ttfName = ttfName;
this.textSize = size;
this.color = color;
}
public NativeFontPaint(String ttfName, Color color) {
this.ttfName = ttfName;
this.color = color;
}
public NativeFontPaint(int size) {
this.textSize = size;
}
public NativeFontPaint(Color color) {
this.color = color;
}
public NativeFontPaint(int size, Color color) {
this.textSize = size;
this.color = color;
}
public int getTextSize() {
return textSize;
}
public void setTextSize(int textSize) {
this.textSize = textSize;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public boolean getFakeBoldText() {
return isFakeBoldText;
}
public void setFakeBoldText(boolean isFakeBoldText) {
this.isFakeBoldText = isFakeBoldText;
}
public boolean getUnderlineText() {
return isUnderlineText;
}
public void setUnderlineText(boolean isUnderlineText) {
this.isUnderlineText = isUnderlineText;
}
public boolean getStrikeThruText() {
return isStrikeThruText;
}
public void setStrikeThruText(boolean isStrikeThruText) {
this.isStrikeThruText = isStrikeThruText;
}
public Color getStrokeColor() {
return strokeColor;
}
public void setStrokeColor(Color strokeColor) {
this.strokeColor = strokeColor;
}
public int getStrokeWidth() {
return strokeWidth;
}
public void setStrokeWidth(int strokeWidth) {
this.strokeWidth = strokeWidth;
}
public void setTTFName(String ttfName) {
this.ttfName = ttfName;
}
public String getTTFName() {
return ttfName;
}
}

View file

@ -0,0 +1,128 @@
package core.java.nativefont;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Pixmap;
import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.GlyphVector;
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.HashMap;
import javax.imageio.ImageIO;
import static javax.swing.UIManager.getColor;
/**
* Created by tian on 2016/10/2.
*/
public class NativeFontDesktop implements NativeFontListener {
private HashMap<String, Font> fonts = new HashMap<String, Font>();
private HashMap<String, FontMetrics> metrics = new HashMap<String, FontMetrics>();
private AttributedString as;
public Pixmap getFontPixmap(String txt, NativeFontPaint vpaint) {
Font font = getFont(vpaint);
FontMetrics fm = metrics.get(vpaint.getName());
int strWidth = fm.stringWidth(txt);
int strHeight = fm.getAscent() + fm.getDescent();
if (strWidth == 0) {
strWidth = strHeight = vpaint.getTextSize();
}
BufferedImage bi = new BufferedImage(strWidth, strHeight,
BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g = bi.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setFont(font);
if (vpaint.getStrokeColor() != null) {
// 描边
GlyphVector v = font.createGlyphVector(fm.getFontRenderContext(),
txt);
Shape shape = v.getOutline();
g.setColor(getColor(vpaint.getColor()));
g.translate(0, fm.getAscent());
g.fill(shape);
g.setStroke(new BasicStroke(vpaint.getStrokeWidth()));
g.setColor(getColor(vpaint.getStrokeColor()));
g.draw(shape);
} else if (vpaint.getUnderlineText() == true) {
// 下划线
AttributedString as = new AttributedString(txt);
as.addAttribute(TextAttribute.FONT, font);
as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
g.setColor(getColor(vpaint.getColor()));
g.drawString(as.getIterator(), 0, fm.getAscent());
} else if (vpaint.getStrikeThruText() == true) {
// 删除线
AttributedString as = new AttributedString(txt);
as.addAttribute(TextAttribute.FONT, font);
as.addAttribute(TextAttribute.STRIKETHROUGH,
TextAttribute.STRIKETHROUGH_ON);
g.setColor(getColor(vpaint.getColor()));
g.drawString(as.getIterator(), 0, fm.getAscent());
} else {
// 普通
g.setColor(getColor(vpaint.getColor()));
g.drawString(txt, 0, fm.getAscent());
}
Pixmap pixmap = null;
try {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ImageIO.write(bi, "png", buffer);
pixmap = new Pixmap(buffer.toByteArray(), 0, buffer.toByteArray().length);
buffer.close();
} catch (IOException e) {
e.printStackTrace();
}
return pixmap;
}
private Font getFont(NativeFontPaint vpaint) {
boolean isBolo = vpaint.getFakeBoldText() || vpaint.getStrokeColor() != null;
Font font = fonts.get(vpaint.getName());
if (font == null) {
if (vpaint.getTTFName().equals("")) {
font = new Font("", isBolo ? Font.BOLD : Font.PLAIN, vpaint.getTextSize());
} else {
try {
ByteArrayInputStream in = new ByteArrayInputStream(Gdx.files.internal(vpaint.getTTFName() + (vpaint.getTTFName()
.endsWith(".ttf") ? "" : ".ttf")).readBytes());
BufferedInputStream fb = new BufferedInputStream(in);
font = Font.createFont(Font.TRUETYPE_FONT, fb).deriveFont(Font.BOLD, vpaint.getTextSize());
fb.close();
in.close();
} catch (FontFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
fonts.put(vpaint.getName(), font);
BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g = bi.createGraphics();
g.setFont(font);
FontMetrics fm = g.getFontMetrics();
metrics.put(vpaint.getName(), fm);
}
return font;
}
}

View file

@ -1,7 +1,6 @@
#Wed Apr 24 09:17:57 IDT 2019
#Sat Aug 24 11:02:13 CST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
distributionSha256Sum=53b71812f18cdb2777e9f1b2a0f2038683907c90bdc406bc64d8b400e1fb2c3b
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip