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

132 lines
2.5 KiB
C#
Raw Normal View History

2025-08-31 06:05:39 +00:00
using Godot;
using System.Collections.Generic;
namespace Rokojori
{
public class FontFXGroup
{
public FontDefinition fontDefinition;
public float scale = 1;
public string characters;
float _width = 0;
public float width
{
get
{
if ( _width == 0 )
{
_width = fontDefinition.GetWidth( characters ) * scale;
}
return _width;
}
}
public List<float> relativeOffsets => fontDefinition.GetOffsets( characters ).Map( o => o * scale );
public List<float> absoluteOffsets;
}
public class FontFXLine
{
public List<FontFXGroup> groups = new List<FontFXGroup>();
public void ComptuteOffsets()
{
var offset = 0f;
for ( int i = 0; i < groups.Count; i++ )
{
var width = groups[ i ].width;
groups[ i ].absoluteOffsets = groups[ i ].relativeOffsets.Map( o => o + offset );
offset += width;
}
}
public List<FontFXLine> LayoutLineWrapped( float width )
{
var lines = new List<FontFXLine>();
var line = new FontFXLine();
var lineWidth = 0f;
groups.ForEach(
( g )=>
{
var groupWidth = g.width;
var nextEnd = lineWidth + groupWidth;
if ( nextEnd > width )
{
lines.Add( line );
line = new FontFXLine();
lineWidth = 0;
}
line.groups.Add( g );
lineWidth += groupWidth;
}
);
lines.Add( line );
return lines;
}
}
public class FontFXLayouter
{
public List<FontFXLine> Layout( string text, FontDefinition font, float maxWidth = 10000000 )
{
var lines = new List<FontFXLine>();
var lexed = WordLexer.Lex( text );
if ( lexed == null )
{
return null;
}
var line = new FontFXLine();
lexed.ForEach(
( l )=>
{
if ( l.isDone )
{
return;
}
if ( l.Is( WordLexer.LineBreak ) )
{
lines.Add( line );
line = new FontFXLine();
return;
}
var group = new FontFXGroup();
group.fontDefinition = font;
group.characters = l.match;
line.groups.Add( group );
}
);
lines.Add( line );
lines = lines.MultiMap( ( line, index ) => line.LayoutLineWrapped( maxWidth ) );
return lines;
}
}
}