Example #1
0
        //TODO: AddFontFromFileTTF
        //ImFont AddFontFromFileTTF(string filename, float size_pixels, ImFontConfig font_cfg_template = null, uint[] glyph_ranges = null)
        //{
        //    int data_size = 0;
        //    byte[] data = ImLoadFileToMemory(filename, "rb", &data_size, 0);
        //    if (data != null)
        //    {
        //        System.Diagnostics.Debug.Assert(false);
        //        return null;
        //    }
        //    ImFontConfig font_cfg = font_cfg_template ?? new ImFontConfig();
        //    if (font_cfg.Name == null)
        //    {
        //        // Store a short copy of filename into into the font name for convenience
        //        font_cfg.Name = System.IO.Path.GetFileName(filename);
        //    }
        //    return AddFontFromMemoryTTF(data, data_size, size_pixels, font_cfg, glyph_ranges);
        //}
        // Transfer ownership of 'ttf_data' to ImFontAtlas, will be deleted after Build()
        ImFont AddFontFromMemoryTTF(byte[] ttf_data, int ttf_size, float size_pixels, ImFontConfig font_cfg_template = null, char[] glyph_ranges = null)
        {
            ImFontConfig font_cfg = font_cfg_template ?? new ImFontConfig();

            System.Diagnostics.Debug.Assert(font_cfg.FontData == null);
            font_cfg.FontData     = ttf_data;
            font_cfg.FontDataSize = ttf_size;
            font_cfg.SizePixels   = size_pixels;
            if (glyph_ranges != null)
            {
                font_cfg.GlyphRanges = glyph_ranges;
            }
            return(AddFont(font_cfg));
        }
Example #2
0
        // 'compressed_ttf_data' still owned by caller. Compress with binary_to_compressed_c.cpp
        unsafe ImFont AddFontFromMemoryCompressedTTF(byte *compressed_ttf_data, uint compressed_ttf_size, float size_pixels, ImFontConfig font_cfg_template = null, char[] glyph_ranges = null)
        {
            uint buf_decompressed_size = STB.stb_decompress_length(compressed_ttf_data);

            //unsigned char* buf_decompressed_data = (unsigned char*)ImGui::MemAlloc(buf_decompressed_size);
            byte[] _buf_decompressed_data = new byte[buf_decompressed_size];

            fixed(byte *buf_decompressed_data = _buf_decompressed_data)
            {
                STB.stb_decompress(buf_decompressed_data, compressed_ttf_data, compressed_ttf_size);

                ImFontConfig font_cfg = font_cfg_template ?? new ImFontConfig();

                System.Diagnostics.Debug.Assert(font_cfg.FontData == null);
                font_cfg.FontDataOwnedByAtlas = true;
                return(AddFontFromMemoryTTF(_buf_decompressed_data, (int)buf_decompressed_size, size_pixels, font_cfg_template, glyph_ranges));
            }
        }
Example #3
0
        internal ImFont AddFontDefault(float fontSize = 13f, ImFontConfig font_cfg_template = null)
        {
            ImFontConfig font_cfg = font_cfg_template ?? new ImFontConfig();// font_cfg_template != null ? *font_cfg_template : ImFontConfig();

            if (font_cfg_template == null)
            {
                font_cfg.OversampleH = font_cfg.OversampleV = 2;
                font_cfg.PixelSnapH  = true;
            }
            if (font_cfg.Name == null)
            {
                font_cfg.Name = "<default>";
            }

            var    ttf_compressed_base85 = STB.GetDefaultCompressedFontDataTTFBase85();
            ImFont font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, fontSize, font_cfg, GetGlyphRangesDefault());

            return(font);
        }
Example #4
0
        //~ImFontAtlas();

        ImFont AddFont(ImFontConfig font_cfg)
        {
            System.Diagnostics.Debug.Assert(font_cfg.FontData != null && font_cfg.FontDataSize > 0);
            System.Diagnostics.Debug.Assert(font_cfg.SizePixels > 0.0f);

            // Create new font
            if (!font_cfg.MergeMode)
            {
                ImFont font = new ImFont();
                //IM_PLACEMENT_NEW(font) ImFont();
                Fonts.push_back(font);
            }

            ConfigData.push_back(font_cfg);
            ImFontConfig new_font_cfg = ConfigData[ConfigData.Size - 1];

            new_font_cfg.DstFont = Fonts[Fonts.Size - 1];
            if (!new_font_cfg.FontDataOwnedByAtlas)
            {
                //new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize);
                new_font_cfg.FontDataOwnedByAtlas = true;
                var fontData = new byte[font_cfg.FontData.Length];
                Array.Copy(font_cfg.FontData, fontData, fontData.Length);
                new_font_cfg.FontData = fontData;

                //memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
            }

            var library = new Library();

            new_font_cfg.Face = new Face(library, new_font_cfg.FontData, 0);
            //new_font_cfg.Face.SetCharSize(0, new_font_cfg.SizePixels, 0, 96);
            new_font_cfg.Face.SetPixelSizes(0, (uint)new_font_cfg.SizePixels);

            // Invalidate texture
            ClearTexData();
            return(Fonts[Fonts.Size - 1]);
        }
Example #5
0
        // 'compressed_ttf_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 paramaeter
        unsafe ImFont AddFontFromMemoryCompressedBase85TTF(string compressed_ttf_data_base85, float size_pixels, ImFontConfig font_cfg = null, char[] glyph_ranges = null)
        {
            uint compressed_ttf_size = (uint)(((compressed_ttf_data_base85.Length + 4) / 5) * 4);

            byte[] _compressed_ttf = new byte[compressed_ttf_size];
            //void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size);
            fixed(byte *compressed_ttf = _compressed_ttf)
            {
                Decode85(compressed_ttf_data_base85, _compressed_ttf);
                ImFont font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);

                //ImGui::MemFree(compressed_ttf);
                return(font);
            }
        }
Example #6
0
        //public ImRect[] PackFont(MaxRectsBinPack packer, Texture2D texture, Texture2D[] textures, int width, int height, int maxSize)
        //{
        //    if (width > maxSize && height > maxSize) return null;
        //    if (width > maxSize || height > maxSize) { int temp = width; width = height; height = temp; }

        //    MaxRectsBinPack bp = new MaxRectsBinPack(width, height);
        //    ImRect[] rects = new ImRect[textures.Length];

        //    for (int i = 0; i < textures.Length; i++)
        //    {
        //        Texture2D tex = textures[i];
        //        ImRect rect = bp.Insert(tex.width, tex.height, MaxRectsBinPack.FreeRectChoiceHeuristic.RectBestAreaFit);
        //        if (rect.width == 0 || rect.height == 0)
        //        {
        //            return PackTextures(texture, textures, width * (width <= height ? 2 : 1), height * (height < width ? 2 : 1), maxSize);
        //        }
        //        rects[i] = rect;
        //    }
        //    texture.Resize(width, height);
        //    texture.SetPixels(new ImColor[width * height]);
        //    for (int i = 0; i < textures.Length; i++)
        //    {
        //        Texture2D tex = textures[i];
        //        ImRect rect = rects[i];
        //        ImColor[] colors = tex.GetPixels();

        //        if (rect.width != tex.width)
        //        {
        //            ImColor[] newColors = tex.GetPixels();

        //            for (int x = 0; x < rect.width; x++)
        //            {
        //                for (int y = 0; y < rect.height; y++)
        //                {
        //                    int prevIndex = ((int)rect.height - (y + 1)) + x * (int)tex.width;
        //                    newColors[x + y * (int)rect.width] = colors[prevIndex];
        //                }
        //            }

        //            colors = newColors;
        //        }

        //        texture.SetPixels((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height, colors);
        //        rect.x /= width;
        //        rect.y /= height;
        //        rect.width /= width;
        //        rect.height /= height;
        //        rects[i] = rect;
        //    }

        //    return rects;

        //}


        internal bool Build()
        {
            System.Diagnostics.Debug.Assert(ConfigData.Size > 0);

            TexID           = null;
            TexWidth        = TexHeight = 0;
            TexUvWhitePixel = new ImVec2(0, 0);
            ClearTexData();

            int total_glyph_count       = 0;
            int total_glyph_range_count = 0;

            for (int input_i = 0; input_i < ConfigData.Size; input_i++)
            {
                ImFontConfig cfg = ConfigData[input_i];
                System.Diagnostics.Debug.Assert(cfg.DstFont != null && (!cfg.DstFont.IsLoaded() || cfg.DstFont.ContainerAtlas == this));

                System.Diagnostics.Debug.Assert(cfg.FontData != null);

                // Count glyphs
                if (cfg.GlyphRanges == null)
                {
                    cfg.GlyphRanges = GetGlyphRangesDefault();
                }

                for (int in_range = 0; cfg.GlyphRanges[in_range] > 0 && cfg.GlyphRanges[in_range + 1] > 0; in_range += 2)
                {
                    total_glyph_count += (cfg.GlyphRanges[in_range + 1] - cfg.GlyphRanges[in_range]) + 1;
                    total_glyph_range_count++;
                }
            }

            // Start packing. We need a known width for the skyline algorithm. Using a cheap heuristic here to decide of width. User can override TexDesiredWidth if they wish.
            // After packing is done, width shouldn't matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
            TexWidth  = (TexDesiredWidth > 0) ? TexDesiredWidth : (total_glyph_count > 4000) ? 4096 : (total_glyph_count > 2000) ? 2048 : (total_glyph_count > 1000) ? 1024 : 512;
            TexHeight = 0;
            int max_tex_height = 1024 * 32;
            var spc            = new MaxRectsBinPack(TexWidth, max_tex_height, false);

            ImVector <ImFontPackingRect> rects = new ImVector <ImFontPackingRect>();

            RenderCustomTexData(spc, 0, rects);

            // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
            for (int input_i = 0; input_i < ConfigData.Size; input_i++)
            {
                ImFontConfig cfg = ConfigData[input_i];
                cfg.Face.SetPixelSizes((uint)(cfg.SizePixels * cfg.OversampleH), (uint)(cfg.SizePixels * cfg.OversampleV));
                for (int in_range = 0; cfg.GlyphRanges[in_range] > 0 && cfg.GlyphRanges[in_range + 1] > 0; in_range += 2)
                {
                    var glyphs       = new List <ImRect>((cfg.GlyphRanges[in_range + 1] - cfg.GlyphRanges[in_range]) + 1);
                    var packedGlyphs = new List <ImRect>((cfg.GlyphRanges[in_range + 1] - cfg.GlyphRanges[in_range]) + 1);
                    for (var range = cfg.GlyphRanges[in_range]; range <= cfg.GlyphRanges[in_range + 1]; range++)
                    {
                        char c = (char)range;

                        uint glyphIndex = cfg.Face.GetCharIndex(c);
                        cfg.Face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);

                        //added padding to keep from bleeding
                        glyphs.Add(new ImRect(0, 0, (int)cfg.Face.Glyph.Metrics.Width + 2, (int)cfg.Face.Glyph.Metrics.Height + 2));
                        spc.Insert((int)cfg.Face.Glyph.Metrics.Width + 2, (int)cfg.Face.Glyph.Metrics.Height + 2, MaxRectsBinPack.FreeRectChoiceHeuristic.RectBestAreaFit);
                    }
                    spc.Insert(glyphs, packedGlyphs, MaxRectsBinPack.FreeRectChoiceHeuristic.RectBestAreaFit);
                    System.Diagnostics.Debug.Assert(glyphs.Count == packedGlyphs.Count);

                    for (var i = 0; i < glyphs.Count; i++)
                    {
                        var c  = (cfg.GlyphRanges[in_range] + i);
                        var g  = glyphs[i];
                        var pg = packedGlyphs[i];

                        var was_packed = pg.width > 0 && pg.height > 0;
                        var r          = new ImFontPackingRect()
                        {
                            id         = c,
                            x          = (int)pg.x + 1,
                            y          = (int)pg.y + 1,
                            w          = (int)pg.width,
                            h          = (int)pg.height,
                            was_packed = was_packed
                        };

                        if (was_packed)
                        {
                            TexHeight = ImGui.Max(TexHeight, r.y + r.h);
                        }

                        rects.push_back(r);
                    }
                }
            }

            // Create texture
            TexHeight       = ImGui.UpperPowerOfTwo(TexHeight);
            TexPixelsAlpha8 = new byte[TexWidth * TexHeight];

            for (int input_i = 0; input_i < ConfigData.Size; input_i++)
            {
                ImFontConfig cfg      = ConfigData[input_i];
                ImFont       dst_font = cfg.DstFont;

                int unscaled_ascent  = cfg.Face.Ascender,
                    unscaled_descent = cfg.Face.Descender;

                float font_scale = cfg.SizePixels / (unscaled_ascent - unscaled_descent); //taken from stbtt_ScaleForPixelHeight
                var   max_height = cfg.Face.Height * font_scale;

                float ascent  = unscaled_ascent * font_scale;
                float descent = unscaled_descent * font_scale;
                if (!cfg.MergeMode)
                {
                    dst_font.ContainerAtlas  = this;
                    dst_font.ConfigData      = cfg;
                    dst_font.ConfigDataCount = 0;
                    dst_font.FontSize        = cfg.SizePixels;
                    dst_font.Ascent          = ascent;
                    dst_font.Descent         = descent;
                    dst_font.Glyphs.resize(0);
                }

                dst_font.ConfigDataCount++;
                float off_y = (cfg.MergeMode && cfg.MergeGlyphCenterV) ? (ascent - dst_font.Ascent) * 0.5f : 0.0f;

                //render
                for (var i = 0; i < rects.Size; i++)
                {
                    var rect = rects[i];
                    //if (rect.id > 0 /*&& rect.was_packed*/)
                    {
                        var codepoint = (ushort)rect.id;
                        if (cfg.MergeMode && dst_font.HasGlyph((char)codepoint))
                        {
                            continue;
                        }

                        uint glyphIndex = cfg.Face.GetCharIndex(codepoint);
                        cfg.Face.LoadGlyph(glyphIndex, LoadFlags.Render, LoadTarget.Normal);
                        cfg.Face.Glyph.RenderGlyph(RenderMode.Normal);

                        var bmp = cfg.Face.Glyph.Bitmap;
                        for (var x = 0; x < bmp.Width; x++)
                        {
                            for (var y = 0; y < bmp.Rows; y++)
                            {
                                TexPixelsAlpha8[(rect.x + x) + ((rect.y + y) * TexWidth)] = bmp.BufferData[x + y * bmp.Pitch];
                            }
                        }
                    }
                }

                cfg.Face.SetPixelSizes((uint)cfg.SizePixels, (uint)cfg.SizePixels);

                //need to calculate origin/baseline
                var top = 0f;
                var bot = 0f;

                for (var i = 0; i < rects.Size; i++)
                {
                    var rect = rects[i];
                    //if (rect.id > 0 /*&& rect.was_packed*/)
                    {
                        var codepoint = (ushort)rect.id;
                        if (cfg.MergeMode && dst_font.HasGlyph((char)codepoint))
                        {
                            continue;
                        }

                        uint glyphIndex = cfg.Face.GetCharIndex(codepoint);
                        cfg.Face.LoadGlyph(glyphIndex, LoadFlags.ComputeMetrics, LoadTarget.Normal);
                        var glyphTop = (float)cfg.Face.Glyph.Metrics.HorizontalBearingY;
                        var glyphBot = (float)(cfg.Face.Glyph.Metrics.Height - cfg.Face.Glyph.Metrics.HorizontalBearingY);
                        if (glyphTop > top)
                        {
                            top = glyphTop;
                        }
                        if (glyphBot > bot)
                        {
                            bot = glyphBot;
                        }
                    }
                }

                //dst_font.FallbackGlyph = null; // Always clear fallback so FindGlyph can return NULL. It will be set again in BuildLookupTable()
                for (var i = 0; i < rects.Size; i++)
                {
                    var rect = rects[i];
                    //if (rect.id > 0 /*&& rect.was_packed*/)
                    {
                        var codepoint = (ushort)rect.id;
                        if (cfg.MergeMode && dst_font.HasGlyph((char)codepoint))
                        {
                            continue;
                        }

                        uint glyphIndex = cfg.Face.GetCharIndex(codepoint);
                        cfg.Face.LoadGlyph(glyphIndex, LoadFlags.ComputeMetrics, LoadTarget.Normal);

                        dst_font.Glyphs.resize(dst_font.Glyphs.Size + 1);
                        var glyph = dst_font.Glyphs[dst_font.Glyphs.Size - 1];
                        glyph.Codepoint = codepoint;

                        glyph.X0 = (int)cfg.Face.Glyph.Metrics.HorizontalBearingX + (float)cfg.Face.Glyph.BitmapLeft;
                        glyph.X1 = (int)cfg.Face.Glyph.Metrics.Width + glyph.X0;
                        glyph.Y0 = top - (float)cfg.Face.Glyph.Metrics.HorizontalBearingY;
                        glyph.Y1 = glyph.Y0 + (float)cfg.Face.Glyph.Metrics.Height;

                        glyph.U0 = rect.x / (float)TexWidth;
                        glyph.V0 = rect.y / (float)TexHeight;
                        glyph.U1 = (rect.x + rect.w) / (float)TexWidth;
                        glyph.V1 = (rect.y + rect.h) / (float)TexHeight;

                        glyph.XAdvance = ((int)cfg.Face.Glyph.Metrics.HorizontalAdvance + cfg.GlyphExtraSpacing.x);  // Bake spacing into XAdvance
                        if (cfg.PixelSnapH)
                        {
                            glyph.XAdvance = (int)(glyph.XAdvance + 0.5f);
                        }
                        dst_font.Glyphs[dst_font.Glyphs.Size - 1] = glyph;
                    }
                }

                cfg.DstFont.BuildLookupTable();
            }

            // Cleanup temporaries
            //ImGui::MemFree(buf_packedchars);
            //ImGui::MemFree(buf_ranges);
            //ImGui::MemFree(tmp_array);

            // Render into our custom data block
            RenderCustomTexData(spc, 1, rects);

            return(true);
        }