Exemple #1
0
        public DrawableFontAtlas GetAtlas(int fontSize, bool pixelFont = false)
        {
            int hash = HashCode.Combine(fontSize, GlyphRasterizer);

            // Check if the atlas is already loaded.
            bool found = _loadedAtlases.TryGetValue(hash, out DrawableFontAtlas atlas);

            if (found)
            {
                return(atlas);
            }

            lock (_loadedAtlases)
            {
                // Recheck as another thread could have built the atlas while waiting on lock.
                found = _loadedAtlases.TryGetValue(hash, out atlas);
                if (found)
                {
                    return(atlas);
                }

                // Get atlas of specified type.
                switch (GlyphRasterizer)
                {
                case GlyphRasterizer.StbTrueType:
                    atlas = new StbDrawableFontAtlas(Font, fontSize, pixelFont);
                    break;

                case GlyphRasterizer.Emotion:
                    atlas = new EmotionRendererDrawableFontAtlas(Font, fontSize, pixelFont);
                    break;

                case GlyphRasterizer.EmotionSDFVer3:
                    atlas = new EmotionSDF3DrawableFontAtlas(Font, fontSize, pixelFont);
                    break;

                case GlyphRasterizer.EmotionSDFVer4:
                    atlas = new EmotionSDFDrawableFontAtlas(Font, fontSize, pixelFont);
                    break;

                default:
                    return(null);
                }

                // Cache default ascii set
                atlas.CacheGlyphs(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");
                _loadedAtlases.Add(hash, atlas);
            }

            return(atlas);
        }
Exemple #2
0
        public void VerifyFontRendering()
        {
            var fonts = new[]
            {
                "Junction-Bold.otf",   // Cff
                "CaslonOS.otf",        // Cff 2 (covers other cases)
                "1980XX.ttf",          // Ttf
                "LatoWeb-Regular.ttf", // Composite
                "Junction-Bold.otf",   // 14 font size
                "Junction-Bold.otf"    // 11 font size
            };

            var names = new[]
            {
                "Junction-Bold",
                "CaslonOS-Regular",
                "1980XX",
                "Lato Regular",
                "Junction-Bold",
                "Junction-Bold"
            };

            var unitsPerEm = new[]
            {
                1000,
                1000,
                1024,
                2000,
                1000,
                1000
            };

            int[] descender =
            {
                -250,
                -360,
                -128,
                -426,
                -250,
                -250
            };

            var ascender = new[]
            {
                750,
                840,
                682,
                1974,
                750,
                750
            };

            var glyphs = new[]
            {
                270,
                279,
                141,
                2164,
                270,
                270
            };

            string[] cachedRender =
            {
                ResultDb.EmotionCffAtlas,
                "",
                ResultDb.EmotionTtAtlas,
                ResultDb.EmotionCompositeAtlas,
                "",
                ""
            };

            int[] fontSizes =
            {
                17,
                17,
                17,
                17,
                14,
                11
            };

            FrameBuffer b = null;

            for (var i = 0; i < fonts.Length; i++)
            {
                Engine.Log.Info($"Running font {fonts[i]} ({i})...", TestRunnerLogger.TestRunnerSrc);
                ReadOnlyMemory <byte> data = Engine.AssetLoader.Get <OtherAsset>($"Fonts/{fonts[i]}")?.Content ?? ReadOnlyMemory <byte> .Empty;
                var f = new Font(data);

                // Verify basic font data.
                Assert.True(f.Valid);
                Assert.True(f.FullName == names[i]);
                Assert.True(f.UnitsPerEm == unitsPerEm[i]);
                Assert.True(f.Descender == descender[i]);
                Assert.True(f.Ascender == ascender[i]);
                Assert.True(f.CharToGlyph.Count == glyphs[i]);

                // Get atlases.
                int fontSize     = fontSizes[i];
                var emotionAtlas = new StbDrawableFontAtlas(f, fontSize, false);
                Runner.ExecuteAsLoop(_ =>
                {
                    var str = "";
                    for (uint j = emotionAtlas.Font.FirstCharIndex; j < emotionAtlas.Font.LastCharIndex; j++)
                    {
                        str += (char)j;
                    }

                    emotionAtlas.CacheGlyphs(str);
                }).WaitOne();
                DrawableFontAtlas packedStbAtlas = RenderFontStbPacked(data.ToArray(), fontSize, emotionAtlas.Texture.Size * 3, (int)f.LastCharIndex + 1, f, out StbTrueType.stbtt_fontinfo stbFont);

                // Compare glyph parsing.
                CompareMetricsWithStb(f, emotionAtlas, stbFont);

                // Compare render metrics.
                foreach (KeyValuePair <char, DrawableGlyph> g in emotionAtlas.Glyphs)
                {
                    DrawableGlyph glyph = packedStbAtlas.Glyphs[g.Key];
                    Assert.Equal(glyph.XAdvance, g.Value.XAdvance);

                    var fontGlyph = g.Value.FontGlyph;
                    int width     = (int)(MathF.Ceiling(fontGlyph.Max.X * emotionAtlas.RenderScale) - MathF.Floor(fontGlyph.Min.X * emotionAtlas.RenderScale));
                    int height    = (int)(MathF.Ceiling(-fontGlyph.Min.Y * emotionAtlas.RenderScale) - MathF.Floor(-fontGlyph.Max.Y * emotionAtlas.RenderScale));

                    Assert.Equal(glyph.Width, width);
                    Assert.Equal(glyph.Height, height);
                }

                // Check if there's a verified render.
                if (string.IsNullOrEmpty(cachedRender[i]))
                {
                    continue;
                }

                // Compare with cached render.
                // ReSharper disable AccessToModifiedClosure

                Runner.ExecuteAsLoop(_ =>
                {
                    if (b == null)
                    {
                        b = new FrameBuffer(emotionAtlas.Texture.Size).WithColor();
                    }
                    else
                    {
                        b.Resize(emotionAtlas.Texture.Size, true);
                    }

                    RenderComposer composer = Engine.Renderer.StartFrame();
                    composer.RenderToAndClear(b);
                    composer.RenderSprite(Vector3.Zero, emotionAtlas.Texture.Size, Color.White, emotionAtlas.Texture);
                    composer.RenderTo(null);
                    Engine.Renderer.EndFrame();
                    Runner.VerifyScreenshot(cachedRender[i], b);
                }).WaitOne();
            }
        }