using Godot; using System.Collections.Generic; namespace Rokojori { [Tool] [GlobalClass] public partial class FontDefinition: Resource { [ExportToolButton( "Clear Cache" )] public Callable refreshButton => Callable.From( ()=> { ClearCache(); } ); [Export] public FontGlyph[] glyphs; [Export] public float defaultWidth = 0.1f; [ExportGroup("Height")] [Export] public float baseToTop; [Export] public float baseToBottom; [ExportGroup("Kerning")] [Export] public float defaultKerning; [Export] public FontKerningPair[] kerningPairs; HashSet _emptyGlyphs = new HashSet(); Dictionary _glyphMap = new Dictionary(); Dictionary _kerning = new Dictionary(); void ClearCache() { _emptyGlyphs = new HashSet(); _glyphMap = new Dictionary(); _kerning = new Dictionary(); } public float GetWidth( string characters ) { var width = 0f; for ( int i = 0; i < characters.Length; i++ ) { width += GetCharacterWidth( characters[ i ] + "" ); if ( i == 0 ) { continue; } var kerning = GetKerning( characters[ i - 1 ], characters[ i ] ); width += kerning; } return width; } public List GetOffsets( string characters ) { var positions = new List(); var position = 0f; for ( int i = 0; i < characters.Length; i++ ) { if ( i != 0 ) { position += GetKerning( characters[ i - 1 ], characters[ i ] ); } positions.Add( position ); position += GetCharacterWidth( characters[ i ] + "" ); } return positions; } public float GetKerning( string characterBefore, string characterAfter ) { var gBefore = GetFontGlyph( characterBefore ); var gAfter = GetFontGlyph( characterAfter ); return GetKerning( gBefore == null ? -1 : gBefore.kerningGroup, gAfter == null ? -1 : gAfter.kerningGroup ); } public float GetKerning( int before, int after ) { var kernID = before + "|" + after; if ( _kerning.ContainsKey( kernID ) ) { return _kerning[ kernID ]; } var kp = kerningPairs.Find( kp => kp.kerningGroupBefore == before && kp.kerningGroupAfter == after ); _kerning[ kernID ] = kp == null ? defaultKerning : kp.kerningWidth; return _kerning[ kernID ]; } public FontGlyph GetFontGlyph( string character ) { if ( _glyphMap.ContainsKey( character ) ) { return _glyphMap[ character ]; } if ( _emptyGlyphs.Contains( character ) ) { return null; } var glyph = glyphs.Find( g => g.characters == character ); if ( glyph == null ) { _emptyGlyphs.Add( character ); return null; } _glyphMap[ character ] = glyph; return glyph; } public float GetCharacterWidth( string character ) { var g = GetFontGlyph( character ); return g == null ? defaultWidth : g.width; } } }