Exemple #1
0
        /// <summary>
        /// Renders the Unicode character to a buffer at the Font Size, and returns true on success
        /// </summary>
        public unsafe bool Render(char unicode, Span <Color> buffer, out int width, out int height)
        {
            if (Charset.TryGetValue(unicode, out var ch) && ch.HasGlyph)
            {
                if (buffer.Length < ch.Width * ch.Height)
                {
                    throw new Exception("Buffer provided isn't large enough to store rendered data");
                }

                if (Font.Disposed)
                    throw new Exception("Cannot get Font data as it is disposed");

                fixed(Color *ptr = buffer)
                {
                    // we actually use the bitmap buffer as our temporary buffer, and fill the pixels out backwards after
                    // kinda weird but it works & saves creating more memory

                    var input = (byte *)ptr;

                    StbTrueType.stbtt_MakeGlyphBitmap(Font.fontInfo, input, ch.Width, ch.Height, ch.Width, Scale, Scale, ch.Glyph);

                    for (int i = ch.Width * ch.Height - 1; i >= 0; i--)
                    {
                        ptr[i] = new Color(input[i], input[i], input[i], input[i]);
                    }
                }

                width  = ch.Width;
                height = ch.Height;
                return(true);
            }

            width = height = 0;
            return(false);
        }
Exemple #2
0
        public static unsafe void CompareMetricsWithStb(Font f, DrawableFontAtlas atlas, StbTrueType.stbtt_fontinfo stbFont)
        {
            var pc = new StbTrueType.stbtt_pack_context();

            StbTrueType.stbtt_PackBegin(pc, (byte *)0, 512, 512, 512, 1, null);

            var cd = new StbTrueType.stbtt_packedchar[f.LastCharIndex + 1];

            StbTrueType.stbrp_rect[] rects;
            fixed(StbTrueType.stbtt_packedchar *charDataPtr = &cd[0])
            {
                var range = new StbTrueType.stbtt_pack_range
                {
                    first_unicode_codepoint_in_range = 0,
                    array_of_unicode_codepoints      = null,
                    num_chars          = (int)f.LastCharIndex + 1,
                    chardata_for_range = charDataPtr,
                    font_size          = -atlas.FontSize
                };

                rects = new StbTrueType.stbrp_rect[f.LastCharIndex + 1];
                fixed(StbTrueType.stbrp_rect *rectPtr = &rects[0])
                {
                    int n = StbTrueType.stbtt_PackFontRangesGatherRects(pc, stbFont, &range, 1, rectPtr);

                    StbTrueType.stbtt_PackFontRangesPackRects(pc, rectPtr, n);
                }
            }

            foreach ((char charIndex, DrawableGlyph atlasGlyph) in atlas.Glyphs)
            {
                FontGlyph glyph = atlasGlyph.FontGlyph;

                var advance = 0;
                var bearing = 0;
                StbTrueType.stbtt_GetCodepointHMetrics(stbFont, charIndex, &advance, &bearing);
                Assert.True(advance == glyph.AdvanceWidth);
                Assert.True(bearing == glyph.LeftSideBearing || glyph.LeftSideBearing == 0); // stb has junk data beyond valid

                var minX = 0;
                var maxX = 0;
                var minY = 0;
                var maxY = 0;
                StbTrueType.stbtt_GetCodepointBitmapBoxSubpixel(stbFont, charIndex, atlas.RenderScale, atlas.RenderScale, 0, 0, &minX, &minY, &maxX, &maxY);

                Rectangle bbox = glyph.GetBBox(atlas.RenderScale);

                Assert.Equal(minX, bbox.X);
                Assert.Equal(minY, bbox.Y);
                Assert.Equal(maxX, bbox.Width);
                Assert.Equal(maxY, bbox.Height);

                Rectangle drawBox = new Rectangle(0, 0, bbox.Width - bbox.X, bbox.Height - bbox.Y);
                drawBox.Size += Vector2.One; // Add padding from stb
                StbTrueType.stbrp_rect rect = rects[charIndex];
                Assert.Equal(rect.w, drawBox.Width);
                Assert.Equal(rect.h, drawBox.Height);
            }
        }
Exemple #3
0
        public int LoadFont(StbTrueType.stbtt_fontinfo font, byte *data, int dataSize)
        {
            var stbError = 0;

            font.userdata = this;
            stbError      = StbTrueType.stbtt_InitFont(font, data, 0);
            return(stbError);
        }
Exemple #4
0
        public FontSize(Font font, int size, string charset)
        {
            if (font.Disposed)
            {
                throw new Exception("Cannot get Font data as it is disposed");
            }

            Font       = font;
            Size       = size;
            Scale      = font.GetScale(size);
            Ascent     = font.Ascent * Scale;
            Descent    = font.Descent * Scale;
            LineGap    = font.LineGap * Scale;
            Height     = Ascent - Descent;
            LineHeight = Height + LineGap;

            for (int i = 0; i < charset.Length; i++)
            {
                // get font info
                var unicode = charset[i];
                var glyph   = font.GetGlyph(unicode);

                if (glyph > 0)
                {
                    unsafe
                    {
                        int advance, offsetX, x0, y0, x1, y1;

                        StbTrueType.stbtt_GetGlyphHMetrics(font.fontInfo, glyph, &advance, &offsetX);
                        StbTrueType.stbtt_GetGlyphBitmapBox(font.fontInfo, glyph, Scale, Scale, &x0, &y0, &x1, &y1);

                        int w = (x1 - x0);
                        int h = (y1 - y0);

                        // define character
                        var ch = new Character
                        {
                            Unicode = unicode,
                            Glyph   = glyph,
                            Width   = w,
                            Height  = h,
                            Advance = advance * Scale,
                            OffsetX = offsetX * Scale,
                            OffsetY = y0
                        };
                        ch.HasGlyph      = (w > 0 && h > 0 && StbTrueType.stbtt_IsGlyphEmpty(font.fontInfo, ch.Glyph) == 0);
                        Charset[unicode] = ch;
                    }
                }
            }
        }
Exemple #5
0
        /// <summary>
        /// Gets the Kerning Value between two Unicode characters at the Font Size, or 0 if there is no Kerning
        /// </summary>
        public float GetKerning(char unicode0, char unicode1)
        {
            if (Charset.TryGetValue(unicode0, out var char0) && Charset.TryGetValue(unicode1, out var char1))
            {
                if (Font.Disposed)
                {
                    throw new Exception("Cannot get Font data as it is disposed");
                }

                return(StbTrueType.stbtt_GetGlyphKernAdvance(Font.fontInfo, char0.Glyph, char1.Glyph) * Scale);
            }

            return(0f);
        }
Exemple #6
0
        public void Begin(int width, int height)
        {
            bitmapWidth  = width;
            bitmapHeight = height;
            _bitmap      = new byte[width * height];
            _context     = new StbTrueType.stbtt_pack_context();

            fixed(byte *pixelsPtr = _bitmap)
            {
                StbTrueType.stbtt_PackBegin(_context, pixelsPtr, width, height, width, 1, null);
            }

            _glyphs = new Dictionary <int, GlyphInfo>();
        }
Exemple #7
0
        public static StbTrueType.stbtt_fontinfo LoadFontStb(byte[] bytes)
        {
            var font = new StbTrueType.stbtt_fontinfo();

            unsafe
            {
                fixed(byte *fontDataPtr = &bytes[0])
                {
                    StbTrueType.stbtt_InitFont(font, fontDataPtr, 0);
                }
            }

            return(font);
        }
Exemple #8
0
            static unsafe string GetName(StbTrueType.stbtt_fontinfo fontInfo, int nameID)
            {
                int length = 0;

                sbyte *ptr = StbTrueType.stbtt_GetFontNameString(fontInfo, &length,
                                                                 StbTrueType.STBTT_PLATFORM_ID_MICROSOFT,
                                                                 StbTrueType.STBTT_MS_EID_UNICODE_BMP,
                                                                 StbTrueType.STBTT_MS_LANG_ENGLISH,
                                                                 nameID);

                if (length > 0)
                {
                    return(new string(ptr, 0, length, Encoding.BigEndianUnicode));
                }

                return("Unknown");
            }
Exemple #9
0
        public static unsafe DrawableFontAtlas RenderFontStbPacked(byte[] ttf, float fontSize, Vector2 atlasSize, int numChars, Font f, out StbTrueType.stbtt_fontinfo fontInfo)
        {
            var atlasObj = new DrawableFontAtlas(f, fontSize);

            fontSize = atlasObj.FontSize;

            fontInfo = new StbTrueType.stbtt_fontinfo();
            fixed(byte *ttPtr = &ttf[0])
            {
                StbTrueType.stbtt_InitFont(fontInfo, ttPtr, 0);

                float scaleFactor = StbTrueType.stbtt_ScaleForMappingEmToPixels(fontInfo, fontSize);
                int   ascent, descent, lineGap;

                StbTrueType.stbtt_GetFontVMetrics(fontInfo, &ascent, &descent, &lineGap);

                atlasSize *= 3; // Needs to be big as the packing sucks, and glyphs getting cut out messes with the tests.
                var pixels = new byte[(int)atlasSize.X * (int)atlasSize.Y];

                var pc = new StbTrueType.stbtt_pack_context();

                fixed(byte *pixelsPtr = pixels)
                {
                    StbTrueType.stbtt_PackBegin(pc, pixelsPtr, (int)atlasSize.X, (int)atlasSize.Y, (int)atlasSize.X, 1, null);
                }

                var cd = new StbTrueType.stbtt_packedchar[numChars];

                fixed(StbTrueType.stbtt_packedchar *charPtr = cd)
                {
                    StbTrueType.stbtt_PackFontRange(pc, ttPtr, 0, -fontSize, 0, numChars, charPtr);
                }

                StbTrueType.stbtt_PackEnd(pc);
                for (var i = 0; i < cd.Length; ++i)
                {
                    var atlasGlyph = DrawableGlyph.CreateForTest(cd[i].xadvance, cd[i].xoff, cd[i].x1 - cd[i].x0, cd[i].y1 - cd[i].y0);
                    atlasGlyph.GlyphUV       = new Rectangle(cd[i].x0, cd[i].y0, atlasGlyph.Width, atlasGlyph.Height);
                    atlasObj.Glyphs[(char)i] = atlasGlyph;
                }
            }

            return(atlasObj);
        }
Exemple #10
0
        /// <summary>
        /// Loads a Font from the byte array. The Font will use this buffer until it is disposed.
        /// </summary>
        public unsafe Font(byte[] buffer)
        {
            fontBuffer = buffer;
            fontHandle = GCHandle.Alloc(fontBuffer, GCHandleType.Pinned);
            fontInfo   = new StbTrueType.stbtt_fontinfo();

            StbTrueType.stbtt_InitFont(fontInfo, (byte *)(fontHandle.AddrOfPinnedObject().ToPointer()), 0);

            FamilyName = GetName(fontInfo, 1);
            StyleName  = GetName(fontInfo, 2);

            // properties
            int ascent, descent, linegap;

            StbTrueType.stbtt_GetFontVMetrics(fontInfo, &ascent, &descent, &linegap);
            Ascent     = ascent;
            Descent    = descent;
            LineGap    = linegap;
            Height     = Ascent - Descent;
            LineHeight = Height + LineGap;
Exemple #11
0
 public static float __tt_getPixelHeightScale(this StbTrueType.stbtt_fontinfo font, float size)
 {
     return((float)(StbTrueType.stbtt_ScaleForPixelHeight(font, (float)(size))));
 }
Exemple #12
0
 public static void __tt_getFontVMetrics(this StbTrueType.stbtt_fontinfo font, int *ascent, int *descent, int *lineGap)
 {
     StbTrueType.stbtt_GetFontVMetrics(font, ascent, descent, lineGap);
 }
Exemple #13
0
 public static int __tt_getGlyphKernAdvance(this StbTrueType.stbtt_fontinfo font, int glyph1, int glyph2)
 {
     return((int)(StbTrueType.stbtt_GetGlyphKernAdvance(font, (int)(glyph1), (int)(glyph2))));
 }
Exemple #14
0
 public static void __tt_renderGlyphBitmap(this StbTrueType.stbtt_fontinfo font, byte *output, int outWidth, int outHeight, int outStride, float scaleX, float scaleY, int glyph)
 {
     StbTrueType.stbtt_MakeGlyphBitmap(font, output, (int)(outWidth), (int)(outHeight), (int)(outStride), (float)(scaleX), (float)(scaleY), (int)(glyph));
 }
Exemple #15
0
 public static int __tt_getGlyphIndex(this StbTrueType.stbtt_fontinfo font, int codepoint)
 {
     return((int)(StbTrueType.stbtt_FindGlyphIndex(font, (int)(codepoint))));
 }
Exemple #16
0
        public void Add(byte[] ttf, float fontPixelHeight,
                        IEnumerable <CharacterRange> characterRanges)
        {
            if (ttf == null || ttf.Length == 0)
            {
                throw new ArgumentNullException(nameof(ttf));
            }

            if (fontPixelHeight <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(fontPixelHeight));
            }

            if (characterRanges == null)
            {
                throw new ArgumentNullException(nameof(characterRanges));
            }

            if (!characterRanges.Any())
            {
                throw new ArgumentException("characterRanges must have a least one value.");
            }

            var fontInfo = StbTrueType.CreateFont(ttf, 0);

            if (fontInfo == null)
            {
                throw new Exception("Failed to init font.");
            }

            var scaleFactor = StbTrueType.stbtt_ScaleForPixelHeight(fontInfo, fontPixelHeight);

            int ascent, descent, lineGap;

            StbTrueType.stbtt_GetFontVMetrics(fontInfo, &ascent, &descent, &lineGap);

            foreach (var range in characterRanges)
            {
                if (range.Start > range.End)
                {
                    continue;
                }

                var cd = new StbTrueType.stbtt_packedchar[range.End - range.Start + 1];
                fixed(StbTrueType.stbtt_packedchar *chardataPtr = cd)
                {
                    StbTrueType.stbtt_PackFontRange(_context, fontInfo.data, 0, fontPixelHeight,
                                                    range.Start,
                                                    range.End - range.Start + 1,
                                                    chardataPtr);
                }

                for (var i = 0; i < cd.Length; ++i)
                {
                    var yOff = cd[i].yoff;
                    yOff += ascent * scaleFactor;

                    var glyphInfo = new GlyphInfo
                    {
                        X        = cd[i].x0,
                        Y        = cd[i].y0,
                        Width    = cd[i].x1 - cd[i].x0,
                        Height   = cd[i].y1 - cd[i].y0,
                        XOffset  = (int)cd[i].xoff,
                        YOffset  = (int)Math.Round(yOff),
                        XAdvance = (int)Math.Round(cd[i].xadvance)
                    };

                    _glyphs[i + range.Start] = glyphInfo;
                }
            }
        }
        public static TtfFontBakerResult Bake(byte[] ttf, float fontPixelHeight,
                                              int bitmapWidth, int bitmapHeight,
                                              IEnumerable <CharacterRange> characterRanges)
        {
            if (ttf == null || ttf.Length == 0)
            {
                throw new ArgumentNullException(nameof(ttf));
            }

            if (fontPixelHeight <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(fontPixelHeight));
            }

            if (bitmapWidth <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bitmapWidth));
            }

            if (bitmapHeight <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bitmapHeight));
            }

            if (characterRanges == null)
            {
                throw new ArgumentNullException(nameof(characterRanges));
            }

            if (!characterRanges.Any())
            {
                throw new ArgumentException("characterRanges must have a least one value.");
            }

            byte[] pixels;
            var    glyphs = new Dictionary <int, GlyphInfo>();

            fixed(byte *ttfPtr = ttf)
            {
                StbTrueType.stbtt_fontinfo fontInfo = new StbTrueType.stbtt_fontinfo();
                if (StbTrueType.stbtt_InitFont(fontInfo, ttfPtr, 0) == 0)
                {
                    throw new Exception("Failed to init font.");
                }

                float scaleFactor = StbTrueType.stbtt_ScaleForPixelHeight(fontInfo, fontPixelHeight);

                int ascent, descent, lineGap;

                StbTrueType.stbtt_GetFontVMetrics(fontInfo, &ascent, &descent, &lineGap);

                pixels = new byte[bitmapWidth * bitmapHeight];
                StbTrueType.stbtt_pack_context pc = new StbTrueType.stbtt_pack_context();
                fixed(byte *pixelsPtr = pixels)
                {
                    StbTrueType.stbtt_PackBegin(pc, pixelsPtr, bitmapWidth,
                                                bitmapHeight, bitmapWidth, 1, null);
                }

                foreach (var range in characterRanges)
                {
                    if (range.Start > range.End)
                    {
                        continue;
                    }

                    var cd = new StbTrueType.stbtt_packedchar[range.End - range.Start + 1];
                    fixed(StbTrueType.stbtt_packedchar *chardataPtr = cd)
                    {
                        StbTrueType.stbtt_PackFontRange(pc, ttfPtr, 0, fontPixelHeight,
                                                        range.Start,
                                                        range.End - range.Start + 1,
                                                        chardataPtr);
                    }

                    for (var i = 0; i < cd.Length; ++i)
                    {
                        var yOff = cd[i].yoff;
                        yOff += ascent * scaleFactor;

                        var glyphInfo = new GlyphInfo
                        {
                            X        = cd[i].x0,
                            Y        = cd[i].y0,
                            Width    = cd[i].x1 - cd[i].x0,
                            Height   = cd[i].y1 - cd[i].y0,
                            XOffset  = (int)cd[i].xoff,
                            YOffset  = (int)Math.Round(yOff),
                            XAdvance = (int)Math.Round(cd[i].xadvance)
                        };

                        glyphs[(char)(i + range.Start)] = glyphInfo;
                    }
                }
            }

            return(new TtfFontBakerResult(glyphs, fontPixelHeight, pixels, bitmapWidth, bitmapHeight));
        }
Exemple #18
0
 public static int __tt_buildGlyphBitmap(this StbTrueType.stbtt_fontinfo font, int glyph, float size, float scale, int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1)
 {
     StbTrueType.stbtt_GetGlyphHMetrics(font, (int)(glyph), advance, lsb);
     StbTrueType.stbtt_GetGlyphBitmapBox(font, (int)(glyph), (float)(scale), (float)(scale), x0, y0, x1, y1);
     return((int)(1));
 }