4 using System.Collections.Generic;
5 using System.Runtime.InteropServices;
8 using SiliconStudio.Core;
9 using SiliconStudio.Core.Diagnostics;
10 using SiliconStudio.Core.Mathematics;
11 using SiliconStudio.Core.Serialization.Contents;
12 using SiliconStudio.Core.Serialization.Converters;
19 namespace SiliconStudio.Paradox.Graphics
24 [ContentSerializer(typeof(DataContentConverterSerializer<DynamicSpriteFontData, SpriteFont>))]
25 [ContentSerializer(typeof(DataContentConverterSerializer<StaticSpriteFontData, SpriteFont>))]
28 private Vector4 nullVector4 = Vector4.Zero;
36 private static readonly
Vector2[] axisDirectionTable = {
44 private static readonly
Vector2[] axisIsMirroredTable = {
51 public static readonly
Logger Logger = GlobalLogger.GetLogger(
"SpriteFont");
55 protected readonly Dictionary<int, float> KerningMap =
new Dictionary<int, float>();
57 public IReadOnlyList<Texture2D> Textures {
get;
protected set; }
62 public float Size {
get;
private set; }
67 public char? DefaultCharacter {
get; set; }
72 public bool IgnoreUnkownCharacters {
get; set; }
79 public float ExtraSpacing {
get; set; }
87 public float ExtraLineSpacing {
get; set; }
92 public bool IsDynamic {
get;
private set; }
98 FontSystem.AllocatedSpriteFonts.Add(
this);
101 IsDynamic = isDynamic;
104 Size = fontData.Size;
105 ExtraSpacing = fontData.ExtraSpacing;
106 ExtraLineSpacing = fontData.ExtraLineSpacing;
107 DefaultCharacter = fontData.DefaultCharacter;
115 FontSystem.AllocatedSpriteFonts.Remove(
this);
130 return fontSize / Size * ExtraSpacing;
140 return fontSize / Size * ExtraLineSpacing;
150 return fontSize / Size * DefaultLineSpacing;
160 return fontSize / Size * BaseOffsetY;
169 return GetExtraLineSpacing(fontSize) + GetFontDefaultLineSpacing(fontSize);
172 internal void InternalDraw(ref StringProxy text, ref InternalDrawCommand drawCommand,
TextAlignment alignment)
177 drawCommand.Origin -= MeasureString(ref text, ref drawCommand.FontSize) * axisIsMirroredTable[(int)drawCommand.SpriteEffects & 3];
181 ForEachGlyph(ref text, ref drawCommand.FontSize, InternalDrawGlyph, ref drawCommand, alignment,
true);
191 var proxyText =
new StringProxy(text);
192 PreGenerateGlyphs(ref proxyText, ref size);
195 internal virtual void PreGenerateGlyphs(ref StringProxy text, ref
Vector2 size)
200 internal void InternalDrawGlyph(ref InternalDrawCommand parameters, ref
Vector2 fontSize, ref
Glyph glyph,
float x,
float y,
float nextx)
202 if (
char.IsWhiteSpace((
char)glyph.Character) || glyph.Subrect.Width == 0 || glyph.Subrect.Height == 0)
207 var offset =
new Vector2(x, y + GetBaseOffsetY(fontSize.Y) + glyph.Offset.Y);
208 Vector2.Modulate(ref offset, ref axisDirectionTable[(int)spriteEffects & 3], out offset);
209 Vector2.Add(ref offset, ref parameters.Origin, out offset);
210 offset.X = (float)Math.Round(offset.X);
211 offset.Y = (float)Math.Round(offset.Y);
216 var glyphRect =
new Vector2(glyph.Subrect.Right - glyph.Subrect.Left, glyph.Subrect.Top - glyph.Subrect.Bottom);
217 Vector2.Modulate(ref glyphRect, ref axisIsMirroredTable[(int)spriteEffects & 3], out offset);
219 var destination =
new RectangleF(parameters.Position.X, parameters.Position.Y, parameters.Scale.X, parameters.Scale.Y);
221 parameters.SpriteBatch.DrawSprite(Textures[glyph.BitmapIndex], ref destination,
true, ref sourceRectangle,
parameters.Color, parameters.Rotation, ref offset, spriteEffects, ImageOrientation.AsIs, parameters.Depth, Swizzle,
true);
224 internal void InternalUIDraw(ref StringProxy text, ref InternalUIDrawCommand drawCommand)
226 if (!IsDynamic && (drawCommand.FontScale.X != 1 || drawCommand.FontScale.Y != 1))
228 drawCommand.SnapText =
false;
229 drawCommand.FontScale = Vector2.One;
232 var fontSize = drawCommand.FontSize * drawCommand.FontScale;
233 var scaledSize =
new Vector2(drawCommand.Size.X * drawCommand.FontScale.X, drawCommand.Size.Y * drawCommand.FontScale.Y);
234 ForEachGlyph(ref text, ref fontSize, InternalUIDrawGlyph, ref drawCommand, drawCommand.Alignment,
true, scaledSize);
237 internal void InternalUIDrawGlyph(ref InternalUIDrawCommand parameters, ref
Vector2 fontSize, ref
Glyph glyph,
float x,
float y,
float nextx)
239 if (
char.IsWhiteSpace((
char)glyph.Character))
242 var xShift = x + glyph.Subrect.Width / 2f;
243 var yShift = y + GetBaseOffsetY(fontSize.Y) + glyph.Offset.Y + glyph.Subrect.Height / 2f;
244 var xScaledShift = xShift / parameters.FontScale.X;
245 var yScaledShift = yShift / parameters.FontScale.Y;
247 var worldMatrix = parameters.WorldMatrix;
248 worldMatrix.M41 += worldMatrix.M11 * xScaledShift + worldMatrix.M21 * yScaledShift;
249 worldMatrix.M42 += worldMatrix.M12 * xScaledShift + worldMatrix.M22 * yScaledShift;
250 worldMatrix.M43 += worldMatrix.M13 * xScaledShift + worldMatrix.M23 * yScaledShift;
252 var elementSize =
new Vector3(glyph.Subrect.Width / parameters.FontScale.X, glyph.Subrect.Height / parameters.FontScale.Y, 0);
255 parameters.Batch.DrawImage(Textures[glyph.BitmapIndex], null, ref worldMatrix, ref sourceRectangle, ref elementSize, ref nullVector4,
256 ref
parameters.Color, parameters.DepthBias, ImageOrientation.AsIs, Swizzle, parameters.SnapText);
266 return MeasureString(text,
new Vector2(Size, Size), text.
Length);
276 return MeasureString(text,
new Vector2(Size, Size), text.
Length);
287 return MeasureString(text,
new Vector2(fontSize, fontSize), text.
Length);
298 return MeasureString(text,
new Vector2(fontSize, fontSize), text.
Length);
309 return MeasureString(text, ref fontSize, text.
Length);
320 return MeasureString(text, ref fontSize, text.
Length);
331 return MeasureString(text, ref fontSize, text.Length);
342 return MeasureString(text, ref fontSize, text.Length);
354 return MeasureString(text, ref fontSize, length);
366 return MeasureString(text, ref fontSize, length);
379 throw new ArgumentNullException(
"text");
381 var proxy =
new StringProxy(text, length);
382 return MeasureString(ref proxy, ref fontSize);
395 throw new ArgumentNullException(
"text");
397 var proxy =
new StringProxy(text, length);
398 return MeasureString(ref proxy, ref fontSize);
403 var result = Vector2.Zero;
404 ForEachGlyph(ref text, ref size, MeasureStringGlyph, ref result,
TextAlignment.Left,
false);
430 private void MeasureStringGlyph(ref
Vector2 result, ref
Vector2 fontSize, ref
Glyph glyph,
float x,
float y,
float nextx)
432 var h = y + GetTotalLineSpacing(fontSize.Y);
433 if (nextx > result.X)
443 private delegate
void GlyphAction<T>(ref T parameters, ref
Vector2 fontSize, ref
Glyph glyph,
float x,
float y,
float nextx);
445 private int FindCariageReturn(ref StringProxy text,
int startIndex)
447 var index = startIndex;
449 while (index < text.Length && text[index] !=
'\n')
455 private void ForEachGlyph<T>(ref StringProxy text, ref
Vector2 fontSize, GlyphAction<T> action, ref
T parameters,
TextAlignment scanOrder,
bool updateGpuResources,
Vector2? elementsize = null)
460 ForGlyph(ref text, ref fontSize, action, ref parameters, 0, text.Length, updateGpuResources);
465 var wholeSize = elementsize.HasValue ? elementsize.Value : MeasureString(ref text, ref fontSize);
470 var endIndex = FindCariageReturn(ref text, 0);
471 while (startIndex < text.Length)
474 var lineSize = Vector2.Zero;
475 ForGlyph(ref text, ref fontSize, MeasureStringGlyph, ref lineSize, startIndex, endIndex, updateGpuResources);
478 var xStart = (scanOrder == TextAlignment.Center) ? (wholeSize.X - lineSize.X) / 2 : wholeSize.X - lineSize.X;
479 ForGlyph(ref text, ref fontSize, action, ref parameters, startIndex, endIndex, updateGpuResources, xStart, yStart);
482 yStart += GetTotalLineSpacing(fontSize.Y);
483 startIndex = endIndex + 1;
484 endIndex = FindCariageReturn(ref text, startIndex);
489 private void ForGlyph<T>(ref StringProxy text, ref
Vector2 fontSize, GlyphAction<T> action, ref
T parameters,
int forStart,
int forEnd,
bool updateGpuResources,
float startX = 0,
float startY = 0)
494 for (var i = forStart; i < forEnd; i++)
496 char character = text[i];
508 y += GetTotalLineSpacing(fontSize.Y);
514 var glyph = GetGlyph(character, ref fontSize, updateGpuResources);
515 if (glyph == null && !IgnoreUnkownCharacters && DefaultCharacter.HasValue)
516 glyph = GetGlyph(DefaultCharacter.Value, ref fontSize, updateGpuResources);
522 float dx = glyph.Offset.X;
525 if (KerningMap != null && KerningMap.TryGetValue(key, out kerningOffset))
528 float nextX = x + glyph.XAdvance + GetExtraSpacing(fontSize.X);
529 action(ref parameters, ref fontSize, ref glyph, x + dx, y, nextX);
539 [StructLayout(LayoutKind.Sequential)]
540 internal struct StringProxy
542 private string textString;
543 private StringBuilder textBuilder;
544 public readonly
int Length;
546 public StringProxy(
string text)
550 Length = text.Length;
553 public StringProxy(StringBuilder text)
557 Length = text.Length;
560 public StringProxy(
string text,
int length)
564 Length = Math.Max(0, Math.Min(length, text.Length));
567 public StringProxy(StringBuilder text,
int length)
571 Length = Math.Max(0, Math.Min(length, text.Length));
574 public bool IsNull {
get {
return textString == null && textBuilder == null; } }
576 public char this[
int index]
580 if (textString != null)
582 return textString[index];
584 return textBuilder[index];
592 internal struct InternalDrawCommand
596 SpriteBatch = spriteBatch;
609 public SpriteBatch SpriteBatch;
615 public float Rotation;
629 internal struct InternalUIDrawCommand
631 public float FontSize;
635 public UIBatch Batch;
637 public Matrix WorldMatrix;
645 public int DepthBias;
647 public bool SnapText;
Vector2 MeasureString(StringBuilder text, Vector2 fontSize, int length)
Returns the width and height of the provided text for a given font size
SiliconStudio.Paradox.Games.Mathematics.Vector2 Vector2
Represents a two dimensional mathematical vector.
Vector2 MeasureString(StringBuilder text, ref Vector2 fontSize)
Returns the width and height of the provided text for a given font size
Vector2 MeasureString(string text, ref Vector2 fontSize)
Returns the width and height of the provided text for a given font size
float Length()
Calculates the length of the vector.
void PreGenerateGlyphs(string text, Vector2 size)
Pre-generate synchronously the glyphs of the character needed to render the provided text at the prov...
Vector2 MeasureString(string text)
Returns the width and height of the provided text for the current font size Size
TextAlignment
Specify the available text alignment when rendering text.
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
override void Destroy()
Disposes of object resources.
Vector2 MeasureString(string text, float fontSize)
Returns the width and height of the provided text for a given font size
The system managing the fonts.
virtual Glyph GetGlyph(char character, ref Vector2 fontSize, bool uploadGpuResources)
Return the glyph associated to provided character at the given size.
Specifies that the object is null.
SpriteFont(FontSystem fontSystem, SpriteFontData fontData, bool isDynamic)
SpriteEffects
Defines sprite mirroring options.
Vector2 MeasureString(StringBuilder text, Vector2 fontSize)
Returns the width and height of the provided text for a given font size
Vector2 MeasureString(StringBuilder text, ref Vector2 fontSize, int length)
Returns the width and height of the provided text for a given font size
Base class for a framework component.
SharpDX.DirectWrite.Font Font
virtual float GetFontDefaultLineSpacing(float fontSize)
Get the value of the font default line spacing for the given font size.
Base implementation for ILogger.
Define a RectangleF. This structure is slightly different from System.Drawing.RectangleF as it is int...
SiliconStudio.Core.Mathematics.Rectangle Rectangle
SpriteFont to use with SpriteBatch. See SpriteFont to learn how to use it.
Vector2 MeasureString(StringBuilder text, float fontSize)
Returns the width and height of the provided text for a given font size
Represents a four dimensional mathematical vector.
virtual float GetBaseOffsetY(float fontSize)
Get the value of the base offset for the given font size.
float GetTotalLineSpacing(float fontSize)
Gets the value of the total line spacing (font default + user defined) in pixels for a given font siz...
virtual float GetExtraLineSpacing(float fontSize)
Get the value of the extra character spacing for the given font size.
readonly FontSystem FontSystem
The SiliconStudio.Paradox.Graphics.Font.FontSystem that is managing this sprite font.
Represents a 32-bit color (4 bytes) in the form of RGBA (in byte order: R, G, B, A).
Description of a glyph (a single character)
Vector2 MeasureString(string text, Vector2 fontSize, int length)
Returns the width and height of the provided text for a given font size
Vector2 MeasureString(string text, Vector2 fontSize)
Returns the width and height of the provided text for a given font size
SwizzleMode
Specify how to swizzle a vector.
virtual bool IsCharPresent(char c)
Checks whether the provided character is present in the character map of the current SpriteFont...
SiliconStudio.Core.Mathematics.Vector3 Vector3
virtual float GetExtraSpacing(float fontSize)
Get the value of the extra line spacing for the given font size.
Vector2 MeasureString(string text, ref Vector2 fontSize, int length)
Returns the width and height of the provided text for a given font size
Structure using the same layout than System.Drawing.Rectangle
_In_ size_t _In_ size_t size
SiliconStudio.Core.Mathematics.Color Color
Data for a SpriteFont object.
SiliconStudio.Core.Mathematics.RectangleF RectangleF
Vector2 MeasureString(StringBuilder text)
Returns the width and height of the provided text for the current font size Size
Represents a 4x4 mathematical matrix.