Files
sbox-public/engine/Sandbox.Engine/Systems/Render/TextRendering/TextRendering.Scope.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

186 lines
5.0 KiB
C#

using System.Text.Json.Serialization;
namespace Sandbox;
public static partial class TextRendering
{
// note: the is like this because eventally TextBlock will take multiple scopes, which would allow us
// to parse html or something and change the styles of text inside a single textblock
/// <summary>
/// Defines a scope of text, all using the same style.
/// </summary>
[Expose]
public struct Scope
{
[KeyProperty]
[JsonInclude, TextArea] public string Text;
[JsonInclude] public Color TextColor;
[JsonInclude, FontName] public string FontName;
[Range( 6, 256 )]
[JsonInclude] public float FontSize;
[Range( 0, 800 )]
[JsonInclude] public int FontWeight;
[JsonInclude] public bool FontItalic;
[Range( 0, 5 )]
[JsonInclude] public float LineHeight;
[JsonInclude] public float LetterSpacing;
[JsonInclude] public float WordSpacing;
[JsonInclude] public Rendering.FilterMode FilterMode;
// this seems stupid, but it's like this because a list would be a pain
// and also would be a bunch of bullshit to hashcode. This is fast.
[Group( "Effects" )]
[JsonInclude] public Outline Outline;
[Group( "Effects" )]
[JsonInclude] public Shadow Shadow;
[Group( "Effects" )]
[JsonInclude] public Outline OutlineUnder;
[Group( "Effects" )]
[JsonInclude] public Shadow ShadowUnder;
public override int GetHashCode()
{
var hc = new HashCode();
hc.Add( Text );
hc.Add( TextColor );
hc.Add( FontName );
hc.Add( FontSize );
hc.Add( FontWeight );
hc.Add( FontItalic );
hc.Add( LineHeight );
hc.Add( LetterSpacing );
hc.Add( WordSpacing );
hc.Add( Outline );
hc.Add( OutlineUnder );
hc.Add( Shadow );
hc.Add( ShadowUnder );
hc.Add( FilterMode );
return hc.ToHashCode();
}
// outlines, shadows, underlines, italic?
// Topten.RichTextKit.Style
public static Scope Default => new Scope
{
Text = "Text",
TextColor = Color.White,
FontName = "Roboto",
FontSize = 64,
FontWeight = 400,
LineHeight = 1,
Shadow = new Shadow() { Color = Color.Black },
ShadowUnder = new Shadow() { Color = Color.Black },
Outline = new Outline() { Color = Color.Blue },
OutlineUnder = new Outline() { Color = Color.Green },
FilterMode = Rendering.FilterMode.Bilinear,
};
public Scope( string text, in Color color, float size, string font = "Roboto", int weight = 400 )
{
Text = text;
TextColor = color;
FontSize = size;
FontName = font;
FontWeight = weight;
LineHeight = 1;
Shadow = new Shadow() { Color = Color.Black };
ShadowUnder = new Shadow() { Color = Color.Black };
Outline = new Outline() { Color = Color.Blue };
OutlineUnder = new Outline() { Color = Color.Green };
FilterMode = Rendering.FilterMode.Bilinear;
}
/// <summary>
/// Measures the rendered size of the text in this <see cref="Scope"/> using its current style settings. This is non trivial
/// but the underlying style is cached, so if you end up drawing it, it'll re-use the cached data anyway.
/// </summary>
/// <returns>
/// A <see cref="Vector2"/> representing the width and height, in pixels, of the rendered text.
/// </returns>
public Vector2 Measure()
{
var block = TextRendering.GetOrCreateTexture( this );
return block.Size;
}
internal void ToStyle( Topten.RichTextKit.Style style )
{
style.FontFamily = FontName;
style.FontSize = FontSize;
style.FontWeight = FontWeight;
style.FontItalic = FontItalic;
style.TextColor = TextColor.ToSk();
style.Underline = Topten.RichTextKit.UnderlineStyle.None;
style.StrikeThrough = Topten.RichTextKit.StrikeThroughStyle.None;
style.LetterSpacing = LetterSpacing;
style.WordSpacing = WordSpacing;
style.LineHeight = LineHeight;
if ( ShadowUnder.Enabled )
{
style.AddEffect( Topten.RichTextKit.TextEffect.DropShadow( ShadowUnder.Color.ToSk(), ShadowUnder.Offset.x, ShadowUnder.Offset.y, ShadowUnder.Size ) );
}
if ( OutlineUnder.Enabled && OutlineUnder.Size > 0 )
{
style.AddEffect( Topten.RichTextKit.TextEffect.Outline( OutlineUnder.Color.ToSk(), OutlineUnder.Size ) );
}
if ( Shadow.Enabled )
{
style.AddEffect( Topten.RichTextKit.TextEffect.DropShadow( Shadow.Color.ToSk(), Shadow.Offset.x, Shadow.Offset.y, Shadow.Size ) );
}
if ( Outline.Enabled && Outline.Size > 0 )
{
style.AddEffect( Topten.RichTextKit.TextEffect.Outline( Outline.Color.ToSk(), Outline.Size ) );
}
}
}
[Expose]
public struct Outline
{
public Outline()
{
}
[JsonInclude][KeyProperty] public bool Enabled;
[JsonInclude] public float Size = 4;
[JsonInclude][KeyProperty] public Color Color = Color.White;
public override int GetHashCode() => HashCode.Combine( Enabled, Size, Color );
}
[Expose]
public struct Shadow
{
public Shadow()
{
}
[JsonInclude][KeyProperty] public bool Enabled;
[JsonInclude][KeyProperty] public float Size = 4;
[JsonInclude][KeyProperty] public Color Color = Color.White;
[JsonInclude] public Vector2 Offset = 4;
public override int GetHashCode() => HashCode.Combine( Enabled, Size, Color, Offset );
}
}