mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-03-15 11:20:39 -07:00
283 lines
11 KiB
Java
283 lines
11 KiB
Java
package mindustry.ui;
|
|
|
|
import arc.*;
|
|
import arc.Graphics.Cursor.*;
|
|
import arc.assets.*;
|
|
import arc.assets.loaders.*;
|
|
import arc.assets.loaders.resolvers.*;
|
|
import arc.files.*;
|
|
import arc.freetype.*;
|
|
import arc.freetype.FreeTypeFontGenerator.*;
|
|
import arc.freetype.FreetypeFontLoader.*;
|
|
import arc.graphics.*;
|
|
import arc.graphics.Pixmap.*;
|
|
import arc.graphics.Texture.*;
|
|
import arc.graphics.g2d.*;
|
|
import arc.graphics.g2d.Font.*;
|
|
import arc.graphics.g2d.PixmapPacker.*;
|
|
import arc.graphics.g2d.TextureAtlas.*;
|
|
import arc.math.geom.*;
|
|
import arc.scene.style.*;
|
|
import arc.scene.ui.layout.*;
|
|
import arc.struct.*;
|
|
import arc.util.*;
|
|
import mindustry.*;
|
|
import mindustry.core.*;
|
|
import mindustry.ctype.*;
|
|
import mindustry.gen.*;
|
|
|
|
import java.util.*;
|
|
|
|
public class Fonts{
|
|
private static final String mainFont = "fonts/font.woff";
|
|
private static final ObjectSet<String> unscaled = ObjectSet.with("iconLarge");
|
|
private static ObjectIntMap<String> unicodeIcons = new ObjectIntMap<>();
|
|
private static ObjectMap<String, String> stringIcons = new ObjectMap<>();
|
|
private static ObjectMap<String, TextureRegion> largeIcons = new ObjectMap<>();
|
|
private static TextureRegion[] iconTable;
|
|
private static int lastCid;
|
|
|
|
public static Font def;
|
|
public static Font outline;
|
|
public static Font chat;
|
|
public static Font icon;
|
|
public static Font iconLarge;
|
|
public static Font tech;
|
|
|
|
public static TextureRegion logicIcon(int id){
|
|
return iconTable[id];
|
|
}
|
|
|
|
public static int getUnicode(String content){
|
|
return unicodeIcons.get(content, 0);
|
|
}
|
|
|
|
public static String getUnicodeStr(String content){
|
|
return stringIcons.get(content, "");
|
|
}
|
|
|
|
/** Called from a static context to make the cursor appear immediately upon startup.*/
|
|
public static void loadSystemCursors(){
|
|
SystemCursor.arrow.set(Core.graphics.newCursor("cursor", cursorScale()));
|
|
SystemCursor.hand.set(Core.graphics.newCursor("hand", cursorScale()));
|
|
SystemCursor.ibeam.set(Core.graphics.newCursor("ibeam", cursorScale()));
|
|
|
|
Core.graphics.restoreCursor();
|
|
}
|
|
|
|
public static int cursorScale(){
|
|
return 1;
|
|
}
|
|
|
|
public static void loadFonts(){
|
|
largeIcons.clear();
|
|
FreeTypeFontParameter param = fontParameter();
|
|
|
|
Core.assets.load("default", Font.class, new FreeTypeFontLoaderParameter(mainFont, param)).loaded = f -> Fonts.def = (Font)f;
|
|
Core.assets.load("chat", Font.class, new FreeTypeFontLoaderParameter(mainFont, param)).loaded = f -> Fonts.chat = (Font)f;
|
|
Core.assets.load("icon", Font.class, new FreeTypeFontLoaderParameter("fonts/icon.ttf", new FreeTypeFontParameter(){{
|
|
size = 30;
|
|
incremental = true;
|
|
characters = "\0";
|
|
}})).loaded = f -> Fonts.icon = (Font)f;
|
|
Core.assets.load("iconLarge", Font.class, new FreeTypeFontLoaderParameter("fonts/icon.ttf", new FreeTypeFontParameter(){{
|
|
size = 48;
|
|
incremental = false;
|
|
characters = "\0" + Iconc.all;
|
|
borderWidth = 5f;
|
|
borderColor = Color.darkGray;
|
|
}})).loaded = f -> Fonts.iconLarge = (Font)f;
|
|
}
|
|
|
|
public static TextureRegion getLargeIcon(String name){
|
|
return largeIcons.get(name, () -> {
|
|
var region = new TextureRegion();
|
|
int code = Iconc.codes.get(name, '\uF8D4');
|
|
var glyph = iconLarge.getData().getGlyph((char)code);
|
|
if(glyph == null) return Core.atlas.find("error");
|
|
region.set(iconLarge.getRegion().texture);
|
|
region.set(glyph.u, glyph.v2, glyph.u2, glyph.v);
|
|
return region;
|
|
});
|
|
}
|
|
|
|
public static void loadContentIcons(){
|
|
Seq<Font> fonts = Seq.with(Fonts.chat, Fonts.def, Fonts.outline);
|
|
Texture uitex = Core.atlas.find("logo").texture;
|
|
int size = (int)(Fonts.def.getData().lineHeight/Fonts.def.getData().scaleY);
|
|
|
|
try(Scanner scan = new Scanner(Core.files.internal("icons/icons.properties").read(512))){
|
|
while(scan.hasNextLine()){
|
|
String line = scan.nextLine();
|
|
String[] split = line.split("=");
|
|
String[] nametex = split[1].split("\\|");
|
|
String character = split[0], texture = nametex[1];
|
|
int ch = Integer.parseInt(character);
|
|
TextureRegion region = Core.atlas.find(texture);
|
|
|
|
if(region.texture != uitex){
|
|
continue;
|
|
//throw new IllegalArgumentException("Font icon '" + texture + "' is not in the UI texture.");
|
|
}
|
|
|
|
unicodeIcons.put(nametex[0], ch);
|
|
stringIcons.put(nametex[0], ((char)ch) + "");
|
|
|
|
Glyph glyph = new Glyph();
|
|
glyph.id = ch;
|
|
glyph.srcX = 0;
|
|
glyph.srcY = 0;
|
|
glyph.width = size;
|
|
glyph.height = (int)((float)region.height / region.width * size);
|
|
glyph.u = region.u;
|
|
glyph.v = region.v2;
|
|
glyph.u2 = region.u2;
|
|
glyph.v2 = region.v;
|
|
glyph.xoffset = 0;
|
|
glyph.yoffset = -size;
|
|
glyph.xadvance = size;
|
|
glyph.kerning = null;
|
|
glyph.fixedWidth = true;
|
|
glyph.page = 0;
|
|
fonts.each(f -> f.getData().setGlyph(ch, glyph));
|
|
}
|
|
}
|
|
|
|
iconTable = new TextureRegion[512];
|
|
iconTable[0] = Core.atlas.find("error");
|
|
lastCid = 1;
|
|
|
|
Vars.content.each(c -> {
|
|
if(c instanceof UnlockableContent u){
|
|
TextureRegion region = Core.atlas.find(u.name + "-icon-logic");
|
|
if(region.found()){
|
|
iconTable[u.iconId = lastCid++] = region;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/** Called from a static context for use in the loading screen.*/
|
|
public static void loadDefaultFont(){
|
|
int max = Gl.getInt(Gl.maxTextureSize);
|
|
|
|
UI.packer = new PixmapPacker(max >= 4096 ? 4096 : 2048, 2048, Format.rgba8888, 2, true);
|
|
FileHandleResolver resolver = new InternalFileHandleResolver();
|
|
Core.assets.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver));
|
|
Core.assets.setLoader(Font.class, null, new FreetypeFontLoader(resolver){
|
|
ObjectSet<FreeTypeFontParameter> scaled = new ObjectSet<>();
|
|
|
|
@Override
|
|
public Font loadSync(AssetManager manager, String fileName, Fi file, FreeTypeFontLoaderParameter parameter){
|
|
if(fileName.equals("outline")){
|
|
parameter.fontParameters.borderWidth = Scl.scl(2f);
|
|
parameter.fontParameters.spaceX -= parameter.fontParameters.borderWidth;
|
|
}
|
|
|
|
if(!scaled.contains(parameter.fontParameters) && !unscaled.contains(fileName)){
|
|
parameter.fontParameters.size = (int)(Scl.scl(parameter.fontParameters.size));
|
|
scaled.add(parameter.fontParameters);
|
|
}
|
|
|
|
parameter.fontParameters.magFilter = TextureFilter.linear;
|
|
parameter.fontParameters.minFilter = TextureFilter.linear;
|
|
parameter.fontParameters.packer = UI.packer;
|
|
return super.loadSync(manager, fileName, file, parameter);
|
|
}
|
|
});
|
|
|
|
FreeTypeFontParameter param = new FreeTypeFontParameter(){{
|
|
borderColor = Color.darkGray;
|
|
incremental = true;
|
|
size = 18;
|
|
}};
|
|
|
|
Core.assets.load("outline", Font.class, new FreeTypeFontLoaderParameter(mainFont, param)).loaded = t -> Fonts.outline = (Font)t;
|
|
|
|
Core.assets.load("tech", Font.class, new FreeTypeFontLoaderParameter("fonts/tech.ttf", new FreeTypeFontParameter(){{
|
|
size = 18;
|
|
}})).loaded = f -> {
|
|
Fonts.tech = (Font)f;
|
|
((Font)f).getData().down *= 1.5f;
|
|
};
|
|
}
|
|
|
|
/** Merges the UI and font atlas together for better performance. */
|
|
public static void mergeFontAtlas(TextureAtlas atlas){
|
|
//grab all textures from the ui page, remove all the regions assigned to it, then copy them over to Fonts.packer and replace the texture in this atlas.
|
|
|
|
//grab old UI texture and regions...
|
|
Texture texture = atlas.find("logo").texture;
|
|
|
|
Page page = UI.packer.getPages().first();
|
|
|
|
Seq<AtlasRegion> regions = atlas.getRegions().select(t -> t.texture == texture);
|
|
for(AtlasRegion region : regions){
|
|
//get new pack rect
|
|
page.setDirty(false);
|
|
Rect rect = UI.packer.pack(region.name + (region.splits != null ? ".9" : ""), atlas.getPixmap(region));
|
|
//set new texture
|
|
region.texture = UI.packer.getPages().first().getTexture();
|
|
//set its new position
|
|
region.set((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
|
|
//add old texture
|
|
atlas.getTextures().add(region.texture);
|
|
}
|
|
|
|
//remove old texture, it will no longer be used
|
|
atlas.getTextures().remove(texture);
|
|
texture.dispose();
|
|
atlas.disposePixmap(texture);
|
|
|
|
page.setDirty(true);
|
|
page.updateTexture(TextureFilter.linear, TextureFilter.linear, false);
|
|
}
|
|
|
|
public static TextureRegionDrawable getGlyph(Font font, char glyph){
|
|
Glyph g = font.getData().getGlyph(glyph);
|
|
if(g == null) throw new IllegalArgumentException("No glyph: " + glyph + " (" + (int)glyph + ")");
|
|
|
|
float size = Math.max(g.width, g.height);
|
|
TextureRegionDrawable draw = new TextureRegionDrawable(new TextureRegion(font.getRegion().texture, g.u, g.v2, g.u2, g.v)){
|
|
@Override
|
|
public void draw(float x, float y, float width, float height){
|
|
Draw.color(Tmp.c1.set(tint).mul(Draw.getColor()).toFloatBits());
|
|
float cx = x + width/2f - g.width/2f, cy = y + height/2f - g.height/2f;
|
|
cx = (int)cx;
|
|
cy = (int)cy;
|
|
Draw.rect(region, cx + g.width/2f, cy + g.height/2f, g.width, g.height);
|
|
}
|
|
|
|
@Override
|
|
public void draw(float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation){
|
|
width *= scaleX;
|
|
height *= scaleY;
|
|
Draw.color(Tmp.c1.set(tint).mul(Draw.getColor()).toFloatBits());
|
|
float cx = x + width/2f - g.width/2f, cy = y + height/2f - g.height/2f;
|
|
cx = (int)cx;
|
|
cy = (int)cy;
|
|
originX = g.width/2f;
|
|
originY = g.height/2f;
|
|
Draw.rect(region, cx + g.width/2f, cy + g.height/2f, g.width, g.height, originX, originY, rotation);
|
|
}
|
|
|
|
@Override
|
|
public float imageSize(){
|
|
return size;
|
|
}
|
|
};
|
|
|
|
draw.setMinWidth(size);
|
|
draw.setMinHeight(size);
|
|
return draw;
|
|
}
|
|
|
|
static FreeTypeFontParameter fontParameter(){
|
|
return new FreeTypeFontParameter(){{
|
|
size = 18;
|
|
shadowColor = Color.darkGray;
|
|
shadowOffsetY = 2;
|
|
incremental = true;
|
|
}};
|
|
}
|
|
}
|