using System.IO; using System.Linq; using System.Text; using Luneraria.UI; using UnityEditor; using UnityEngine; using UnityEngine.TextCore.LowLevel; using UnityEngine.TextCore.Text; using UnityEngine.UIElements; namespace Luneraria.EditorTools { /// /// Builds Settings/LuneUi.asset (U3): static SDF font atlases from the variable fonts of the /// reference (assets/fonts, OFL). Unity's text engine has no weight axis; FreeType loads the /// named instances through the face index (named instance << 16): Cantarell Regular (3) and /// Bold (4), Cinzel Bold (2). The atlases hold every character the HUD texts use, so the player /// never needs the font files. /// Unity -batchmode -projectPath . -executeMethod Luneraria.EditorTools.LuneUiAssetsBuilder.Build -logFile - /// public static class LuneUiAssetsBuilder { public const string AssetPath = "Assets/Luneraria/Settings/LuneUi.asset"; const string Fonts = "Assets/Luneraria/UI/Fonts/"; public static void Build() { var assets = AssetDatabase.LoadAssetAtPath(AssetPath); if (assets == null) { assets = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(assets, AssetPath); } assets.Text = Font("Cantarell-VF.otf", 3, "Cantarell-Regular"); assets.TextBold = Font("Cantarell-VF.otf", 4, "Cantarell-Bold"); assets.Display = Font("Cinzel-VF.ttf", 2, "Cinzel-Bold"); assets.Theme = AssetDatabase.LoadAssetAtPath("Assets/Luneraria/UI/LuneRuntimeTheme.tss"); EditorUtility.SetDirty(assets); AssetDatabase.SaveAssets(); Debug.Log("LUNE_UI built " + AssetPath); if (Application.isBatchMode) EditorApplication.Exit(0); } /// Printable ASCII, Latin-1 and the punctuation and symbols of the HUD texts. public static string Characters() { var text = new StringBuilder(); for (char c = (char)32; c < 127; c++) text.Append(c); for (char c = (char)160; c <= 255; c++) text.Append(c); text.Append("–—‘’‚“”„•…‰‹›€→←↑↓−×★≈≤≥∞·ŒœŠšŽžŸ"); return new string(text.ToString().Distinct().ToArray()); } static FontAsset Font(string file, int namedInstance, string name) { string path = Fonts + name + ".asset"; if (AssetDatabase.LoadAssetAtPath(path) != null) AssetDatabase.DeleteAsset(path); string source = Path.GetFullPath(Fonts + file); FontAsset font = FontAsset.CreateFontAsset(source, namedInstance << 16, 64, 8, GlyphRenderMode.SDFAA, 1024, 1024); if (font == null) throw new System.InvalidOperationException("Font asset failed: " + file + " instance " + namedInstance); font.name = name; AssetDatabase.CreateAsset(font, path); if (!font.TryAddCharacters(Characters(), out string missing)) Debug.LogWarning("LUNE_UI " + name + " misses: " + missing); for (int index = 0; index < font.atlasTextures.Length; index++) { Texture2D atlas = font.atlasTextures[index]; if (atlas == null) continue; atlas.name = name + " Atlas " + index; AssetDatabase.AddObjectToAsset(atlas, font); } font.material.name = name + " Material"; AssetDatabase.AddObjectToAsset(font.material, font); font.atlasPopulationMode = AtlasPopulationMode.Static; // A static atlas needs no source at runtime: keep no machine path and never clear it in builds. var serialized = new SerializedObject(font); serialized.FindProperty("m_SourceFontFilePath").stringValue = Fonts + file; serialized.FindProperty("m_ClearDynamicDataOnBuild").boolValue = false; serialized.ApplyModifiedPropertiesWithoutUndo(); EditorUtility.SetDirty(font); AssetDatabase.SaveAssets(); Debug.Log(string.Format("LUNE_UI font {0}: {1} / {2}, {3} glyphs, {4} atlas(es)", name, font.faceInfo.familyName, font.faceInfo.styleName, font.glyphTable.Count, font.atlasTextures.Length)); return font; } } }