rj-action-library/Runtime/Rendering/FontFX/FontDefinition.cs

149 lines
3.2 KiB
C#
Raw Permalink Normal View History

2025-08-31 06:05:39 +00:00
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<string> _emptyGlyphs = new HashSet<string>();
Dictionary<string,FontGlyph> _glyphMap = new Dictionary<string, FontGlyph>();
Dictionary<string,float> _kerning = new Dictionary<string, float>();
void ClearCache()
{
_emptyGlyphs = new HashSet<string>();
_glyphMap = new Dictionary<string, FontGlyph>();
_kerning = new Dictionary<string, float>();
}
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<float> GetOffsets( string characters )
{
var positions = new List<float>();
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;
}
}
}