mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
Optimize font loading to happen on startup without blocking UI thread any more than necessary
This commit is contained in:
@@ -79,7 +79,10 @@ public class Forge implements ApplicationListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
FModel.initialize(splashScreen.getProgressBar());
|
FModel.initialize(splashScreen.getProgressBar());
|
||||||
|
|
||||||
splashScreen.getProgressBar().setDescription("Finishing startup...");
|
splashScreen.getProgressBar().setDescription("Loading fonts");
|
||||||
|
FSkinFont.preloadAll();
|
||||||
|
|
||||||
|
splashScreen.getProgressBar().setDescription("Finishing startup");
|
||||||
|
|
||||||
Gdx.app.postRunnable(new Runnable() {
|
Gdx.app.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import forge.sound.IAudioClip;
|
|||||||
import forge.toolbox.FOptionPane;
|
import forge.toolbox.FOptionPane;
|
||||||
import forge.toolbox.GuiChoose;
|
import forge.toolbox.GuiChoose;
|
||||||
import forge.util.ITriggerEvent;
|
import forge.util.ITriggerEvent;
|
||||||
import forge.util.ThreadUtil;
|
|
||||||
import forge.util.WaitCallback;
|
import forge.util.WaitCallback;
|
||||||
import forge.util.WaitRunnable;
|
import forge.util.WaitRunnable;
|
||||||
import forge.util.gui.SGuiChoose;
|
import forge.util.gui.SGuiChoose;
|
||||||
@@ -79,7 +78,7 @@ public class GuiMobile implements IGuiBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isGuiThread() {
|
public boolean isGuiThread() {
|
||||||
return !ThreadUtil.isGameThread();
|
return Thread.currentThread().getName().startsWith("LWJGL");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -8,21 +8,22 @@ import com.badlogic.gdx.files.FileHandle;
|
|||||||
import com.badlogic.gdx.graphics.Pixmap;
|
import com.badlogic.gdx.graphics.Pixmap;
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
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.PixmapPacker;
|
import com.badlogic.gdx.graphics.g2d.PixmapPacker;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
|
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
|
||||||
import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
|
import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
|
||||||
|
import forge.FThreads;
|
||||||
import forge.util.Utils;
|
import forge.util.Utils;
|
||||||
|
|
||||||
public class FSkinFont {
|
public class FSkinFont {
|
||||||
public static final int MIN_FONT_SIZE = Math.round(8 / Utils.MAX_RATIO);
|
public static final int MIN_FONT_SIZE = Math.round(8 / Utils.MAX_RATIO);
|
||||||
|
public static final int MAX_FONT_SIZE = Math.round(72 / Utils.MAX_RATIO);
|
||||||
|
|
||||||
private static final String TTF_FILE = "font1.ttf";
|
private static final String TTF_FILE = "font1.ttf";
|
||||||
private static final Map<Integer, FSkinFont> fonts = new HashMap<Integer, FSkinFont>();
|
private static final Map<Integer, FSkinFont> fonts = new HashMap<Integer, FSkinFont>();
|
||||||
private static final int FONT_PAGE_SIZE = 256;
|
|
||||||
private static final int MAX_FONT_SIZE = 72; //don't generate fonts larger than this, use scaling instead
|
|
||||||
|
|
||||||
public static FSkinFont get(final int size0) {
|
public static FSkinFont get(final int size0) {
|
||||||
FSkinFont skinFont = fonts.get(size0);
|
FSkinFont skinFont = fonts.get(size0);
|
||||||
@@ -43,6 +44,13 @@ public class FSkinFont {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//pre-load all supported font sizes
|
||||||
|
public static void preloadAll() {
|
||||||
|
for (int size = MIN_FONT_SIZE; size <= MAX_FONT_SIZE; size++) {
|
||||||
|
get(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void updateAll() {
|
public static void updateAll() {
|
||||||
for (FSkinFont skinFont : fonts.values()) {
|
for (FSkinFont skinFont : fonts.values()) {
|
||||||
skinFont.updateFont();
|
skinFont.updateFont();
|
||||||
@@ -66,46 +74,51 @@ public class FSkinFont {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateFont() {
|
private void updateFont() {
|
||||||
float scale = 1;
|
|
||||||
int fontSize = (int)Utils.scaleMax(size);
|
int fontSize = (int)Utils.scaleMax(size);
|
||||||
try {
|
|
||||||
if (fontSize > MAX_FONT_SIZE) { //scale if larger than max font size
|
|
||||||
scale = (float)fontSize / (float)MAX_FONT_SIZE;
|
|
||||||
fontSize = MAX_FONT_SIZE;
|
|
||||||
}
|
|
||||||
String fontName = "f" + fontSize;
|
String fontName = "f" + fontSize;
|
||||||
FileHandle fontFile = Gdx.files.absolute(FSkin.getFontDir() + fontName + ".fnt");
|
FileHandle fontFile = Gdx.files.absolute(FSkin.getFontDir() + fontName + ".fnt");
|
||||||
if (fontFile.exists()) {
|
if (fontFile.exists()) {
|
||||||
font = new BitmapFont(fontFile);
|
final BitmapFontData data = new BitmapFontData(fontFile, false);
|
||||||
|
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() { //font must be initialized on UI thread
|
||||||
|
font = new BitmapFont(data, (TextureRegion)null, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
FileHandle ttfFile = Gdx.files.absolute(FSkin.getDir() + TTF_FILE);
|
FileHandle ttfFile = Gdx.files.absolute(FSkin.getDir() + TTF_FILE);
|
||||||
font = generateFont(ttfFile, fontName, fontSize);
|
generateFont(ttfFile, fontName, fontSize);
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
if (font == null) {
|
|
||||||
font = new BitmapFont(); //use scaled default font as fallback
|
|
||||||
scale = (float)fontSize / 15; //default font has size 15
|
|
||||||
}
|
|
||||||
font.setUseIntegerPositions(true); //prevent parts of text getting cut off at times
|
|
||||||
if (scale != 1) {
|
|
||||||
font.setScale(scale);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BitmapFont generateFont(FileHandle ttfFile, String fontName, int fontSize) {
|
private void generateFont(final FileHandle ttfFile, final String fontName, final int fontSize) {
|
||||||
if (!ttfFile.exists()) { return null; }
|
if (!ttfFile.exists()) { return; }
|
||||||
|
|
||||||
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(ttfFile);
|
final FreeTypeFontGenerator generator = new FreeTypeFontGenerator(ttfFile);
|
||||||
|
|
||||||
PixmapPacker packer = new PixmapPacker(FONT_PAGE_SIZE, FONT_PAGE_SIZE, Pixmap.Format.RGBA8888, 2, false);
|
//approximate optimal page size
|
||||||
FreeTypeFontGenerator.FreeTypeBitmapFontData fontData = generator.generateData(fontSize, FreeTypeFontGenerator.DEFAULT_CHARS, false, packer);
|
int pageSize;
|
||||||
Array<PixmapPacker.Page> pages = packer.getPages();
|
if (fontSize >= 28) {
|
||||||
TextureRegion[] texRegions = new TextureRegion[pages.size];
|
pageSize = 256;
|
||||||
for (int i=0; i<pages.size; i++) {
|
}
|
||||||
|
else {
|
||||||
|
pageSize = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
//only generate images for characters that could be used by Forge
|
||||||
|
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\"!?'.,;:()[]{}<>|/@\\^$-%+=#_&*";
|
||||||
|
|
||||||
|
final PixmapPacker packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 2, false);
|
||||||
|
final FreeTypeFontGenerator.FreeTypeBitmapFontData fontData = generator.generateData(fontSize, chars, false, packer);
|
||||||
|
final Array<PixmapPacker.Page> pages = packer.getPages();
|
||||||
|
|
||||||
|
//finish generating font on UI thread
|
||||||
|
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
TextureRegion[] textureRegions = new TextureRegion[pages.size];
|
||||||
|
for (int i = 0; i < pages.size; i++) {
|
||||||
PixmapPacker.Page p = pages.get(i);
|
PixmapPacker.Page p = pages.get(i);
|
||||||
Texture texture = new Texture(new PixmapTextureData(p.getPixmap(), p.getPixmap().getFormat(), false, false)) {
|
Texture texture = new Texture(new PixmapTextureData(p.getPixmap(), p.getPixmap().getFormat(), false, false)) {
|
||||||
@Override
|
@Override
|
||||||
@@ -115,10 +128,10 @@ public class FSkinFont {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
|
texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
|
||||||
texRegions[i] = new TextureRegion(texture);
|
textureRegions[i] = new TextureRegion(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
BitmapFont font = new BitmapFont(fontData, texRegions, false);
|
font = new BitmapFont(fontData, textureRegions, true);
|
||||||
|
|
||||||
//create .fnt and .png files for font
|
//create .fnt and .png files for font
|
||||||
FileHandle fontFile = Gdx.files.absolute(FSkin.getFontDir() + fontName + ".fnt");
|
FileHandle fontFile = Gdx.files.absolute(FSkin.getFontDir() + fontName + ".fnt");
|
||||||
@@ -130,6 +143,7 @@ public class FSkinFont {
|
|||||||
|
|
||||||
generator.dispose();
|
generator.dispose();
|
||||||
packer.dispose();
|
packer.dispose();
|
||||||
return font;
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user