Beispiel #1
0
 /// <summary>
 /// Creates a <see cref="TrippyFontFile"/> holding information for multiple fonts with the same size.
 /// </summary>
 /// <remarks>All the fonts have the same character range.</remarks>
 public static TrippyFontFile CreateFontFile(ReadOnlySpan <string> fontFiles, float size, char firstChar = ' ', char lastChar = '~', Color?backgroundColor = null)
 {
     IGlyphSource[] glyphSources = new IGlyphSource[fontFiles.Length];
     for (int i = 0; i < glyphSources.Length; i++)
     {
         glyphSources[i] = new FontGlyphSource(FontInstance.LoadFont(fontFiles[i]), size, firstChar, lastChar);
     }
     return(FontBuilder.CreateFontFile(glyphSources, backgroundColor));
 }
Beispiel #2
0
 /// <summary>
 /// Creates a <see cref="TrippyFontFile"/> holding information for multiple fonts.
 /// </summary>
 /// <remarks>All the fonts have the same character range.</remarks>
 public static TrippyFontFile CreateFontFile(ReadOnlySpan <Font> fonts, char firstChar = ' ', char lastChar = '~', Color?backgroundColor = null)
 {
     IGlyphSource[] glyphSources = new IGlyphSource[fonts.Length];
     for (int i = 0; i < fonts.Length; i++)
     {
         glyphSources[i] = new FontGlyphSource(fonts[i], firstChar, lastChar);
     }
     return(FontBuilder.CreateFontFile(glyphSources, backgroundColor));
 }
Beispiel #3
0
        protected override void Initialize()
        {
            base.Initialize();

            Materials = new DefaultMaterialSet(RenderCoordinator);

            Alignment.Pressed += (s, e) => {
                Text.Alignment = (HorizontalAlignment)(((int)Text.Alignment + 1) % 7);
            };
            CharacterWrap.Pressed += (s, e) => {
                Text.CharacterWrap = !Text.CharacterWrap;
            };
            WordWrap.Pressed += (s, e) => {
                Text.WordWrap = !Text.WordWrap;
            };
            Hinting.Pressed += (s, e) => {
                var ftf = (FreeTypeFont)LatinFont;
                ftf.Hinting = !ftf.Hinting;
                ftf.Invalidate();
                ftf         = (FreeTypeFont)UniFont;
                ftf.Hinting = !ftf.Hinting;
                ftf.Invalidate();
                Text.Invalidate();
            };
            Margin.Pressed += (s, e) => {
                var ftf = (FreeTypeFont)LatinFont;
                ftf.GlyphMargin = (ftf.GlyphMargin + 1) % 6;
                ftf.Invalidate();
                Text.Invalidate();
            };
            Monochrome.Pressed += (s, e) => {
                var ftf = (FreeTypeFont)LatinFont;
                ftf.Monochrome = !ftf.Monochrome;
                ftf.Invalidate();
                ftf            = (FreeTypeFont)UniFont;
                ftf.Monochrome = !ftf.Monochrome;
                ftf.Invalidate();
                Text.Invalidate();
            };
            FreeType.Pressed += (s, e) => {
                if (ActiveFont == FallbackFont)
                {
                    ActiveFont = new SpriteFontGlyphSource(DutchAndHarley);
                    TextScale  = 1f;
                }
                else
                {
                    ActiveFont = FallbackFont;
                    TextScale  = 2f;
                }
                Text.GlyphSource = ActiveFont;
                Text.Scale       = TextScale;
            };
        }
Beispiel #4
0
        protected override void LoadContent()
        {
            SpriteFont = new SpriteFontGlyphSource(Content.Load <SpriteFont>("font"));
            LatinFont  = new FreeTypeFont(RenderCoordinator, "FiraSans-Regular.otf")
            {
                SizePoints = 40, DPIPercent = 200, GlyphMargin = 4, Gamma = 1.6
            };
            if (false)
            {
                LatinFont = new FreeTypeFont(RenderCoordinator, "cambria.ttc")
                {
                    SizePoints = 40, DPIPercent = 200, GlyphMargin = 4, Gamma = 1.6
                }
            }
            ;
            UniFont = new FreeTypeFont(RenderCoordinator, @"C:\Windows\Fonts\ArialUni.ttf")
            {
                SizePoints = 30, DPIPercent = 200, GlyphMargin = 4, Gamma = 1.6
            };
            FallbackFont = new FallbackGlyphSource(LatinFont, UniFont);

            ActiveFont = FallbackFont;

            Text = new DynamicStringLayout(ActiveFont, TestText)
            {
                // Alignment = HorizontalAlignment.Right,
                AlignToPixels = GlyphPixelAlignment.FloorY,
                CharacterWrap = true,
                WordWrap      = true,
                Scale         = 2f,
                ReverseOrder  = true
            };
            Text2 = new DynamicStringLayout(ActiveFont, TestText2)
            {
                AlignToPixels = GlyphPixelAlignment.FloorY,
                CharacterWrap = true,
                WordWrap      = true,
                Scale         = 2f,
                ReverseOrder  = true
            };
        }
Beispiel #5
0
        public void DrawString(
            IGlyphSource glyphSource, string text,
            Vector2 position, Color?color = null, float scale     = 1, DrawCallSortKey?sortKey = null,
            int characterSkipCount        = 0, int characterLimit = int.MaxValue,
            int?layer             = null, bool?worldSpace = null,
            BlendState blendState = null, SamplerState samplerState = null
            )
        {
            using (var buffer = BufferPool <BitmapDrawCall> .Allocate(text.Length)) {
                var layout = glyphSource.LayoutString(
                    text, new ArraySegment <BitmapDrawCall>(buffer.Data),
                    position, color, scale, sortKey.GetValueOrDefault(NextSortKey),
                    characterSkipCount, characterLimit, alignToPixels: true
                    );

                DrawMultiple(
                    layout,
                    layer: layer, worldSpace: worldSpace, blendState: blendState, samplerState: samplerState
                    );

                buffer.Clear();
            }
        }
Beispiel #6
0
        // Yuck :(
        public static StringLayout LayoutString(
            this IGlyphSource glyphSource, AbstractString text, ArraySegment <BitmapDrawCall>?buffer = null,
            Vector2?position         = null, Color?color = null, float scale = 1,
            DrawCallSortKey sortKey  = default(DrawCallSortKey),
            int characterSkipCount   = 0, int?characterLimit = null,
            float xOffsetOfFirstLine = 0, float?lineBreakAtX = null,
            bool alignToPixels       = false,
            Dictionary <char, KerningAdjustment> kerningAdjustments = null,
            bool wordWrap = false, char wrapCharacter = '\0'
            )
        {
            var state = new StringLayoutEngine {
                position           = position,
                color              = color,
                scale              = scale,
                sortKey            = sortKey,
                characterSkipCount = characterSkipCount,
                characterLimit     = characterLimit,
                xOffsetOfFirstLine = xOffsetOfFirstLine,
                lineBreakAtX       = lineBreakAtX,
                alignToPixels      = alignToPixels,
                characterWrap      = lineBreakAtX.HasValue,
                wordWrap           = wordWrap,
                wrapCharacter      = wrapCharacter,
                buffer             = buffer.GetValueOrDefault(default(ArraySegment <BitmapDrawCall>))
            };

            state.Initialize();

            using (state) {
                var segment = state.AppendText(
                    glyphSource, text, kerningAdjustments
                    );

                return(state.Finish());
            }
        }
Beispiel #7
0
        protected override void OnLoadContent(bool isReloading)
        {
            var margin = 6;

            LatinFont = new FreeTypeFont(RenderCoordinator, "FiraSans-Regular.otf")
            {
                SizePoints         = 40, DPIPercent = 200, GlyphMargin = margin, Gamma = 1.6,
                DefaultGlyphColors =
                {
                    { (uint)'h', Color.Red }
                }
            };
            if (false)
            {
                LatinFont = new FreeTypeFont(RenderCoordinator, "cambria.ttc")
                {
                    SizePoints = 40, DPIPercent = 200, GlyphMargin = margin, Gamma = 1.6
                }
            }
            ;
            UniFont = new FreeTypeFont(RenderCoordinator, @"C:\Windows\Fonts\msgothic.ttc")
            {
                SizePoints = 30, DPIPercent = 200, GlyphMargin = margin, Gamma = 1.6
            };
            FallbackFont   = new FallbackGlyphSource(LatinFont, UniFont);
            SmallLatinFont = new FreeTypeFont.FontSize((FreeTypeFont)LatinFont, 40 * 0.75f);

            ActiveFont = FallbackFont;

            Content.RootDirectory = "";
            DutchAndHarley        = Content.Load <SpriteFont>("DutchAndHarley");

            Text = new DynamicStringLayout(ActiveFont, SelectedString)
            {
                AlignToPixels         = GlyphPixelAlignment.RoundXY,
                CharacterWrap         = true,
                WordWrap              = true,
                Scale                 = TextScale,
                ReverseOrder          = true,
                RichText              = true,
                HideOverflow          = true,
                RichTextConfiguration = new RichTextConfiguration {
                    MarkedStringProcessor = ProcessMarkedString,
                    Styles = new Dictionary <string, RichStyle> {
                        { "quick", new RichStyle {
                              Color = Color.Yellow
                          } },
                        { "brown", new RichStyle {
                              Color = Color.Brown, Scale = 2
                          } }
                    },
                    GlyphSources = new Dictionary <string, IGlyphSource> {
                        { "large", LatinFont },
                        { "small", SmallLatinFont }
                    },
                    ImageProvider = Text_ImageProvider
                },
                WordWrapCharacters = new uint[] {
                    '\\', '/', ':', ','
                },
            };

            for (int i = 0; i < Images.Length; i++)
            {
                using (var s = File.OpenRead($"{i + 1}.png"))
                    Images[i] = Texture2D.FromStream(Graphics.GraphicsDevice, s);
            }
        }
Beispiel #8
0
 public DynamicStringLayout(IGlyphSource font = null, string text = "")
 {
     _GlyphSource = font;
     _Text        = text;
 }
Beispiel #9
0
 public DynamicStringLayout(SpriteFont font, string text = "")
 {
     _GlyphSource = new SpriteFontGlyphSource(font);
     _Text        = text;
 }
Beispiel #10
0
 /// <summary>
 /// Creates a <see cref="TrippyFontFile"/> holding information for a single font.
 /// </summary>
 /// <param name="glyphSources">The <see cref="IGlyphSource"/> for getting the information of the font.</param>
 /// <param name="backgroundColor">The background color of the generated image. Null for transparent.</param>
 public static TrippyFontFile CreateFontFile(IGlyphSource glyphSources, Color?backgroundColor = null)
 {
     return(CreateFontFile(new IGlyphSource[] { glyphSources }, backgroundColor));
 }
Beispiel #11
0
 public static Dictionary <char, KerningAdjustment> GetDefaultKerningAdjustments(IGlyphSource font)
 {
     // FIXME
     if (font is SpriteFontGlyphSource)
     {
         Dictionary <char, KerningAdjustment> result;
         _DefaultKerningAdjustments.TryGetValue(((SpriteFontGlyphSource)font).Font, out result);
         return(result);
     }
     else
     {
         return(null);
     }
 }
Beispiel #12
0
        public ArraySegment <BitmapDrawCall> AppendText(
            IGlyphSource font, AbstractString text,
            Dictionary <char, KerningAdjustment> kerningAdjustments = null
            )
        {
            if (!IsInitialized)
            {
                throw new InvalidOperationException("Call Initialize first");
            }

            if (font == null)
            {
                throw new ArgumentNullException("font");
            }
            if (text.IsNull)
            {
                throw new ArgumentNullException("text");
            }

            EnsureBufferCapacity(bufferWritePosition + text.Length);

            if (kerningAdjustments == null)
            {
                kerningAdjustments = StringLayout.GetDefaultKerningAdjustments(font);
            }

            var effectiveScale = scale / font.DPIScaleFactor;

            var drawCall = default(BitmapDrawCall);

            drawCall.MultiplyColor = color.GetValueOrDefault(Color.White);
            drawCall.ScaleF        = effectiveScale;
            drawCall.SortKey       = sortKey;

            float x = 0;
            float?defaultLineSpacing = null;

            for (int i = 0, l = text.Length; i < l; i++)
            {
                var  ch = text[i];
                bool isWhiteSpace = char.IsWhiteSpace(ch),
                     forcedWrap = false, lineBreak = false,
                     deadGlyph = false;
                Glyph             glyph;
                KerningAdjustment kerningAdjustment;

                if (ch == '\r')
                {
                    if (((i + 1) < l) && (text[i + 1] == '\n'))
                    {
                        i += 1;
                    }

                    lineBreak = true;
                }
                else if (ch == '\n')
                {
                    lineBreak = true;
                }

                if (isWhiteSpace)
                {
                    wordStartWritePosition = -1;
                    wordWrapSuppressed     = false;
                }
                else
                {
                    if (wordStartWritePosition < 0)
                    {
                        wordStartWritePosition = bufferWritePosition;
                        wordStartOffset        = characterOffset;
                    }
                }

                deadGlyph = !font.GetGlyph(ch, out glyph);

                float effectiveLineSpacing = glyph.LineSpacing;
                if (deadGlyph)
                {
                    if (currentLineSpacing.HasValue)
                    {
                        effectiveLineSpacing = currentLineSpacing.Value;
                    }
                    else if (defaultLineSpacing.HasValue)
                    {
                        effectiveLineSpacing = defaultLineSpacing.Value;
                    }
                    else
                    {
                        Glyph space;
                        if (font.GetGlyph(' ', out space))
                        {
                            defaultLineSpacing = effectiveLineSpacing = space.LineSpacing;
                        }
                    }
                }

                if ((kerningAdjustments != null) && kerningAdjustments.TryGetValue(ch, out kerningAdjustment))
                {
                    glyph.LeftSideBearing  += kerningAdjustment.LeftSideBearing;
                    glyph.Width            += kerningAdjustment.Width;
                    glyph.RightSideBearing += kerningAdjustment.RightSideBearing;
                }

                x =
                    characterOffset.X +
                    glyph.LeftSideBearing +
                    glyph.RightSideBearing +
                    glyph.Width + glyph.CharacterSpacing;

                if ((x * effectiveScale) >= lineBreakAtX)
                {
                    if (
                        !deadGlyph &&
                        (colIndex > 0) &&
                        !isWhiteSpace
                        )
                    {
                        forcedWrap = true;
                    }
                }

                if (forcedWrap)
                {
                    var currentWordSize = x - wordStartOffset.X;

                    if (wordWrap && !wordWrapSuppressed && (currentWordSize * effectiveScale <= lineBreakAtX))
                    {
                        WrapWord(buffer, wordStartOffset, wordStartWritePosition, bufferWritePosition - 1, effectiveScale, effectiveLineSpacing);
                        wordWrapSuppressed = true;
                        lineBreak          = true;
                    }
                    else if (characterWrap)
                    {
                        characterOffset.X  = xOffsetOfWrappedLine;
                        characterOffset.Y += effectiveLineSpacing;

                        maxX = Math.Max(maxX, currentLineMaxX * effectiveScale);
                        wordStartWritePosition = bufferWritePosition;
                        wordStartOffset        = characterOffset;
                        lineBreak = true;
                    }
                }

                if (lineBreak)
                {
                    if (!forcedWrap)
                    {
                        characterOffset.X  = xOffsetOfNewLine;
                        characterOffset.Y += effectiveLineSpacing;
                        maxX = Math.Max(maxX, currentLineMaxX * effectiveScale);
                    }

                    initialLineXOffset            = characterOffset.X;
                    currentLineMaxX               = 0;
                    currentLineWhitespaceMaxX     = 0;
                    currentLineWhitespaceMaxXLeft = 0;
                    rowIndex += 1;
                    colIndex  = 0;
                }

                if (deadGlyph)
                {
                    characterSkipCount--;
                    if (characterLimit.HasValue)
                    {
                        characterLimit--;
                    }
                    continue;
                }

                // HACK: Recompute after wrapping
                x =
                    characterOffset.X +
                    glyph.LeftSideBearing +
                    glyph.RightSideBearing +
                    glyph.Width + glyph.CharacterSpacing;

                characterOffset.X += glyph.CharacterSpacing;

                lastCharacterBounds = Bounds.FromPositionAndSize(
                    characterOffset * effectiveScale, new Vector2(
                        glyph.LeftSideBearing + glyph.Width + glyph.RightSideBearing,
                        glyph.LineSpacing
                        ) * effectiveScale
                    );

                if ((rowIndex == 0) && (colIndex == 0))
                {
                    firstCharacterBounds = lastCharacterBounds;
                }

                characterOffset.X += glyph.LeftSideBearing;

                if (colIndex == 0)
                {
                    characterOffset.X = Math.Max(characterOffset.X, 0);
                }

                if (characterSkipCount <= 0)
                {
                    if (characterLimit.HasValue && characterLimit.Value <= 0)
                    {
                        break;
                    }

                    var glyphPosition = new Vector2(
                        actualPosition.X + (glyph.XOffset + characterOffset.X) * effectiveScale,
                        actualPosition.Y + (glyph.YOffset + characterOffset.Y) * effectiveScale
                        );

                    if (!isWhiteSpace)
                    {
                        if (bufferWritePosition >= buffer.Count)
                        {
                            EnsureBufferCapacity(bufferWritePosition);
                        }

                        drawCall.Texture       = glyph.Texture;
                        drawCall.TextureRegion = glyph.Texture.BoundsFromRectangle(ref glyph.BoundsInTexture);
                        Snap(glyphPosition, out drawCall.Position);

                        // HACK so that the alignment pass can detect rows. We strip this later.
                        if (alignment != HorizontalAlignment.Left)
                        {
                            drawCall.SortKey.Order = rowIndex;
                        }

                        buffer.Array[buffer.Offset + bufferWritePosition] = drawCall;

                        currentLineMaxX = Math.Max(currentLineMaxX, x);
                        maxY            = Math.Max(maxY, (characterOffset.Y + effectiveLineSpacing) * effectiveScale);

                        bufferWritePosition += 1;
                        drawCallsWritten    += 1;
                    }
                    else
                    {
                        currentLineWhitespaceMaxXLeft = Math.Max(currentLineWhitespaceMaxXLeft, characterOffset.X);
                        currentLineWhitespaceMaxX     = Math.Max(currentLineWhitespaceMaxX, x);
                    }

                    characterLimit--;
                }
                else
                {
                    characterSkipCount--;
                }

                characterOffset.X += (glyph.Width + glyph.RightSideBearing);
                currentLineSpacing = glyph.LineSpacing;
                maxLineSpacing     = Math.Max(maxLineSpacing, effectiveLineSpacing);

                colIndex += 1;
            }

            var segment = new ArraySegment <BitmapDrawCall>(
                buffer.Array, buffer.Offset, drawCallsWritten
                );

            maxX = Math.Max(maxX, currentLineMaxX * effectiveScale);

            return(segment);
        }