Exemple #1
0
        public static Vector2 MeasureTextLine(this IFont font, string text, float fontHeight, int start, int length, float letterSpacing)
        {
            FontChar prevChar = null;
            var      size     = new Vector2(0, fontHeight);
            float    width    = 0;

            for (int i = 0; i < length; i++)
            {
                char ch = text[i + start];
                if (ch == '\n')
                {
                    size.Y  += fontHeight;
                    width    = 0;
                    prevChar = null;
                    continue;
                }
                var fontChar = font.CharSource.Get(ch, fontHeight);
                if (fontChar == FontChar.Null)
                {
                    continue;
                }
                float scale = fontChar.Height != 0.0f ? fontHeight / fontChar.Height : 0.0f;
                width   += scale * (fontChar.ACWidths.X + fontChar.Kerning(prevChar) + fontChar.Width + fontChar.ACWidths.Y + letterSpacing);
                size.X   = Math.Max(size.X, width);
                prevChar = fontChar;
            }
            return(size);
        }
Exemple #2
0
        private FontChar CreateFontChar(char code)
        {
            var glyph = fontRenderer.Render(code, fontHeight);

            if (texture == null)
            {
                CreateNewFontTexture();
            }
            if (glyph == null)
            {
                return(null);
            }

            // We add 1px left and right padding to each char on the texture and also to the UV
            // so that chars will be blurred correctly after stretching or drawing to float position.
            // And we compensate this padding by ACWidth, so that the text will take the same space.
            // See "texture bleeding"
            const int padding = 1;

            // Space between characters on the texture
            const int spacing          = 1;
            var       paddedGlyphWidth = glyph.Width + padding * 2;

            if (position.X + paddedGlyphWidth + spacing >= texture.ImageSize.Width)
            {
                position.X           = 0;
                position.Y          += fontHeight + spacing + lineAdditionalHeight;
                lineAdditionalHeight = 0;
            }
            if (glyph.VerticalOffset < -lineAdditionalHeight)
            {
                lineAdditionalHeight = -glyph.VerticalOffset;
            }
            if (position.Y + fontHeight + spacing + lineAdditionalHeight >= texture.ImageSize.Height)
            {
                CreateNewFontTexture();
                position = IntVector2.Zero;
            }
            CopyGlyphToTexture(glyph, texture, position + new IntVector2(padding, 0));
            var fontChar = new FontChar {
                Char           = code,
                UV0            = (Vector2)position / (Vector2)texture.ImageSize,
                UV1            = ((Vector2)position + new Vector2(paddedGlyphWidth, fontHeight)) / (Vector2)texture.ImageSize,
                ACWidths       = glyph.ACWidths - Vector2.One * padding,
                Width          = paddedGlyphWidth,
                Height         = fontHeight,
                RgbIntensity   = glyph.RgbIntensity,
                KerningPairs   = glyph.KerningPairs,
                TextureIndex   = textureIndex,
                VerticalOffset = Math.Min(0, glyph.VerticalOffset)
            };

            position.X += paddedGlyphWidth + spacing;
            return(fontChar);
        }
Exemple #3
0
        private FontChar CreateFontChar(char code)
        {
            var glyph = FontRenderer.Render(code, fontHeight);

            if (texture == null)
            {
                CreateNewFontTexture();
            }
            if (glyph == null)
            {
                return(null);
            }
            // Space between characters on the texture
            const int spacing      = 1;
            var       paddedWidth  = glyph.Width + Padding * 2;
            var       paddedHeight = fontHeight + Padding * 2;

            if (position.X + paddedWidth + spacing >= texture.ImageSize.Width)
            {
                position.X           = 0;
                position.Y          += paddedHeight + spacing + lineAdditionalHeight;
                lineAdditionalHeight = 0;
            }
            if (glyph.VerticalOffset < -lineAdditionalHeight)
            {
                lineAdditionalHeight = -glyph.VerticalOffset;
            }
            if (position.Y + paddedHeight + spacing + lineAdditionalHeight >= texture.ImageSize.Height)
            {
                CreateNewFontTexture();
                position = IntVector2.Zero;
            }
            CopyGlyphToTexture(glyph, texture, position + new IntVector2(Padding, Padding));
            var fontChar = new FontChar {
                Char           = code,
                UV0            = (Vector2)position / (Vector2)texture.ImageSize,
                UV1            = ((Vector2)position + new Vector2(paddedWidth, paddedHeight)) / (Vector2)texture.ImageSize,
                ACWidths       = glyph.ACWidths,
                Width          = glyph.Width,
                Height         = fontHeight,
                RgbIntensity   = glyph.RgbIntensity,
                KerningPairs   = glyph.KerningPairs,
                TextureIndex   = textureIndex,
                VerticalOffset = Math.Min(0, glyph.VerticalOffset),
                // Invisible glyphs doesn't have padding
                Padding = char.IsWhiteSpace(code) ? 0 : Padding,
            };

            position.X += paddedWidth + spacing;
            return(fontChar);
        }
Exemple #4
0
 public float Kerning(FontChar prevChar)
 {
     if (prevChar != null && prevChar.KerningPairs != null)
     {
         foreach (var pair in prevChar.KerningPairs)
         {
             if (pair.Char == Char)
             {
                 return(pair.Kerning);
             }
         }
     }
     return(0);
 }
Exemple #5
0
 private static bool ContainsKerningFor(this FontChar fontChar, char @char)
 {
     if (fontChar.KerningPairs != null)
     {
         foreach (var pair in fontChar.KerningPairs)
         {
             if (pair.Char == @char)
             {
                 return(true);
             }
         }
     }
     return(false);
 }
Exemple #6
0
        private static void AddOrReplaceKerningPair(this FontChar fontChar, char @char, float kerning)
        {
            var pairs = fontChar.KerningPairs = fontChar.KerningPairs ?? new List <KerningPair>();

            for (int i = 0; i < pairs.Count; i++)
            {
                var pair = pairs[i];
                if (pair.Char == @char)
                {
                    pair.Kerning = kerning;
                    pairs[i]     = pair;
                    return;
                }
            }
            pairs.Add(new KerningPair {
                Char = @char, Kerning = kerning
            });
        }
Exemple #7
0
        public static void DrawTextLine(
            IFont font, Vector2 position, string text, Color4 color, float fontHeight, int start, int length, float letterSpacing,
            SpriteList list, Action <int, Vector2, Vector2> onDrawChar = null, int tag = -1)
        {
            int j = 0;

            if (list != null)
            {
                for (int i = 0; i < length; i++)
                {
                    char ch = text[i + start];
                    if (ch != '\n' && ch != '\r' && font.CharSource.Get(ch, fontHeight) != FontChar.Null)
                    {
                        ++j;
                    }
                }
            }
            // Use array instead of list to reduce memory consumption.
            var chars = new SpriteList.CharDef[j];

            j = 0;
            FontChar prevChar          = null;
            var      halfLetterSpacing = letterSpacing * .5f;
            float    savedX            = position.X;

            for (int i = 0; i < length; i++)
            {
                char ch = text[i + start];
                if (ch == '\n')
                {
                    onDrawChar?.Invoke(i, position, Vector2.Down * fontHeight);
                    position.X  = savedX;
                    position.Y += fontHeight;
                    prevChar    = null;
                    continue;
                }
                else if (ch == '\r')
                {
                    continue;
                }
                FontChar fontChar = font.CharSource.Get(ch, fontHeight);
                if (fontChar == FontChar.Null)
                {
                    onDrawChar?.Invoke(i, position, Vector2.Down * fontHeight);
                    continue;
                }
                var scale = fontChar.Height != 0.0f ? fontHeight / fontChar.Height : 0.0f;
                // Pen Position + Bearing + Kerning gives a proper letter position
                // but we have to subtract left padding in order to avoid extra spacing
                position.X += scale * (fontChar.ACWidths.X + fontChar.Kerning(prevChar) + halfLetterSpacing - fontChar.Padding);
                var size         = new Vector2(scale * fontChar.PaddedWidth, fontHeight + scale * (fontChar.PaddedHeight - fontChar.VerticalOffset));
                var charPosition = new Vector2(position.X, position.Y + scale * (fontChar.VerticalOffset - fontChar.Padding));
                if (font.RoundCoordinates)
                {
                    charPosition = new Vector2(charPosition.X.Round(), charPosition.Y.Round());
                }
                onDrawChar?.Invoke(i, charPosition, size);
                chars[j].FontChar = fontChar;
                chars[j].Position = charPosition;
                ++j;
                // We have to add left padding to get actual letter position
                // Width + (Horizontal Advance - Bearing) will give a proper pen position for next letter
                position.X += scale * (fontChar.Width + fontChar.ACWidths.Y + halfLetterSpacing + fontChar.Padding);
                prevChar    = fontChar;
            }
            list.Add(font, color, fontHeight, chars, tag);
        }
Exemple #8
0
        public static void DrawTextLine(
            IFont font, Vector2 position, string text, Color4 color, float fontHeight, int start, int length, float letterSpacing,
            SpriteList list, Action <int, Vector2, Vector2> onDrawChar = null, int tag = -1)
        {
            int j = 0;

            if (list != null)
            {
                for (int i = 0; i < length; i++)
                {
                    char ch = text[i + start];
                    if (ch != '\n' && ch != '\r' && font.Chars.Get(ch, fontHeight) != FontChar.Null)
                    {
                        ++j;
                    }
                }
            }
            // Use array instead of list to reduce memory consumption.
            var chars = new SpriteList.CharDef[j];

            j = 0;
            FontChar prevChar = null;
            float    savedX   = position.X;

            for (int i = 0; i < length; i++)
            {
                char ch = text[i + start];
                if (ch == '\n')
                {
                    onDrawChar?.Invoke(i, position, Vector2.Down * fontHeight);
                    position.X  = savedX;
                    position.Y += fontHeight;
                    prevChar    = null;
                    continue;
                }
                else if (ch == '\r')
                {
                    continue;
                }
                FontChar fontChar = font.Chars.Get(ch, fontHeight);
                if (fontChar == FontChar.Null)
                {
                    onDrawChar?.Invoke(i, position, Vector2.Down * fontHeight);
                    continue;
                }
                float scale  = fontChar.Height != 0.0f ? fontHeight / fontChar.Height : 0.0f;
                var   xDelta = scale * (fontChar.ACWidths.X + fontChar.Kerning(prevChar) + letterSpacing);
                position.X += xDelta;
                var     size = new Vector2(scale * fontChar.Width, fontHeight - fontChar.VerticalOffset);
                Vector2 roundPos;
                if (font.RoundCoordinates)
                {
                    roundPos = new Vector2(position.X.Round(), position.Y.Round() + fontChar.VerticalOffset);
                    onDrawChar?.Invoke(i, new Vector2((position.X - xDelta).Round(), position.Y.Round()), size);
                }
                else
                {
                    roundPos = new Vector2(position.X, position.Y + fontChar.VerticalOffset);
                    onDrawChar?.Invoke(i, new Vector2(position.X - xDelta, position.Y), size);
                }
                chars[j].FontChar = fontChar;
                chars[j].Position = roundPos;
                ++j;
                position.X += scale * (fontChar.Width + fontChar.ACWidths.Y);
                prevChar    = fontChar;
            }
            list.Add(font, color, fontHeight, chars, tag);
        }