Edit

kc3-lang/angle/src/libANGLE/gen_overlay_fonts.py

Branch :

  • Show log

    Commit

  • Author : Alexey Knyazev
    Date : 2021-03-10 10:31:39
    Hash : 90d18b03
    Message : Upgrade overlay fonts generator to Python 3 Bug: angleproject:5707 Change-Id: I809669d7a7de16ed2e098f59067c8e1d9c44a75c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2773292 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Alexey Knyazev <lexa.knyazev@gmail.com>

  • src/libANGLE/gen_overlay_fonts.py
  • #!/usr/bin/env vpython3
    #
    # [VPYTHON:BEGIN]
    # wheel: <
    #   name: "infra/python/wheels/freetype-py/${vpython_platform}"
    #   version: "version:2.1.0.post1"
    # >
    # [VPYTHON:END]
    
    # Copyright 2019 The ANGLE Project Authors. All rights reserved.
    # Use of this source code is governed by a BSD-style license that can be
    # found in the LICENSE file.
    #
    # gen_vk_overlay_fonts.py:
    #  Code generation for overlay fonts.  Should be run if the font file under overlay/ is changed,
    #  or the font sizes declared in this file are modified.  The font is assumed to be monospace.
    #  The output will contain ASCII characters in order from ' ' to '~'.  The output will be images
    #  with 3 rows of 32 characters each.
    #  NOTE: don't run this script directly. Run scripts/run_code_generation.py.
    
    import sys
    
    if len(sys.argv) < 2:
        from freetype import *
    
    out_file_cpp = 'Overlay_font_autogen.cpp'
    out_file_h = 'Overlay_font_autogen.h'
    font_file = 'overlay/DejaVuSansMono-Bold.ttf'
    
    template_out_file_h = u"""// GENERATED FILE - DO NOT EDIT.
    // Generated by {script_name} using {font_file}.
    //
    // Copyright 2019 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // {out_file_name}:
    //   Autogenerated overlay font data.
    
    #include "libANGLE/Overlay.h"
    
    namespace gl
    {{
    namespace overlay
    {{
    constexpr int kFontCount = {font_count};
    constexpr int kFontGlyphWidths[kFontCount] = {{ {font_glyph_widths} }};
    constexpr int kFontGlyphHeights[kFontCount] = {{ {font_glyph_heights} }};
    constexpr int kFontCharactersPerRow = 32;
    constexpr int kFontCharactersPerCol = 3;
    constexpr int kFontCharacters = kFontCharactersPerRow * kFontCharactersPerCol;
    constexpr int kFontImageWidth = {max_font_width} * kFontCharactersPerRow;
    constexpr int kFontImageHeight = {max_font_height} * kFontCharactersPerCol;
    {font_layers}
    }}  // namespace overlay
    }}  // namespace gl
    
    """
    
    template_out_file_cpp = u"""// GENERATED FILE - DO NOT EDIT.
    // Generated by {script_name} using images from {font_file}.
    //
    // Copyright 2019 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // {out_file_name}:
    //   Autogenerated overlay font data.
    
    #include "libANGLE/Overlay.h"
    #include "libANGLE/Overlay_font_autogen.h"
    
    #include <numeric>
    
    namespace gl
    {{
    using namespace overlay;
    
    // Save binary size if the font images are never to be used.
    #if ANGLE_ENABLE_OVERLAY
    namespace
    {{
    constexpr int kFontWidths[kFontCount] = {{ {font_layer_widths} }};
    constexpr int kFontHeights[kFontCount] = {{ {font_layer_heights} }};
    
    {font_data}
    
    // Returns a bit with the value of the pixel.
    template<int kFontWidth, int kFontHeight>
    uint32_t GetFontLayerPixel(const uint32_t fontImage[kFontHeight][kFontWidth / 32], int x, int y)
    {{
        ASSERT(x >= 0 && x < kFontWidth && y >= 0 && y < kFontHeight);
        return fontImage[y][x / 32] >> (x % 32) & 1;
    }}
    
    inline uint32_t GetFontPixel(int layer, int x, int y)
    {{
        switch (layer)
        {{
        {get_font_layer_pixel}
        default:
            UNREACHABLE();
            return 0;
        }}
    }}
    
    }}  // anonymous namespace
    
    void OverlayState::initFontData(uint8_t *fontData) const
    {{
        constexpr int kFontDataLayerSize = kFontImageWidth * kFontImageHeight;
    
        // Unpack the font bitmap into R8_UNORM format.  Border pixels are given a 0.5 value for better
        // font visibility.
        for (int layer = 0; layer < kFontCount; ++layer)
        {{
            memset(fontData, 0, kFontDataLayerSize);
            for (int y = 0; y < kFontHeights[layer]; ++y)
            {{
                for (int x = 0; x < kFontWidths[layer]; ++x)
                {{
                    uint32_t src     = GetFontPixel(layer, x, y);
                    uint8_t dstValue = src ? 255 : 0;
                    fontData[y * kFontImageWidth + x] = dstValue;
                }}
            }}
            fontData += kFontDataLayerSize;
        }}
    }}
    #else
    void OverlayState::initFontData(uint8_t *fontData) const
    {{
        memset(fontData, 0, kFontCount * kFontImageWidth * kFontImageHeight * sizeof(*fontData));
    }}
    #endif
    }}  // namespace gl
    """
    
    template_get_font_layer_pixel = u"""case {layer}:
        return GetFontLayerPixel<kFontWidths[{layer}], kFontHeights[{layer}]>({font_image}, x, y);
    """
    
    
    def main():
        if len(sys.argv) == 2 and sys.argv[1] == 'inputs':
            # disabled because of issues on Windows. http://anglebug.com/3892
            # print(font_file)
            return
        if len(sys.argv) == 2 and sys.argv[1] == 'outputs':
            print(','.join([out_file_cpp, out_file_h]))
            return
    
        font_defs = [('large', 36), ('medium', 23), ('small', 14)]
        chars = ' !"#$%&\'()*+,-./0123456789:;<=>?' + \
                '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + \
                '`abcdefghijklmnopqrstuvwxyz{|}~ '
        output_rows = 3
        output_cols = 32
        assert (len(chars) == output_rows * output_cols)
    
        font_glyph_widths = []
        font_glyph_heights = []
        font_layers = []
        font_data = []
        get_font_layer_pixel = []
        current_font_layer = 0
    
        # Load the font file.
        face = Face(font_file)
        assert (face.is_fixed_width)
    
        for font_name, font_size in font_defs:
    
            # Since the font is fixed width, we can retrieve its size right away.
            face.set_char_size(font_size << 6)
            glyph_width = face.size.max_advance >> 6
            glyph_ascender = face.size.ascender >> 6
            glyph_descender = face.size.descender >> 6
            glyph_height = glyph_ascender - glyph_descender
    
            font_tag = font_name.capitalize()
            font_layer = str(current_font_layer)
            font_layer_symbol = 'kFontLayer' + font_tag
            font_array_name = 'kFontImage' + font_tag
            font_width = 'kFontWidths[' + font_layer_symbol + ']'
            font_height = 'kFontHeights[' + font_layer_symbol + ']'
    
            # Font pixels are packed in 32-bit values.
            font_array_width = output_cols * glyph_width // 32
            font_array_height = output_rows * glyph_height
            font_array = [[0] * font_array_width for i in range(font_array_height)]
    
            for charIndex in range(len(chars)):
                char = chars[charIndex]
                base_x = (charIndex % output_cols) * glyph_width
                base_y = (charIndex // output_cols) * glyph_height
    
                # Render the character.
                face.load_char(char)
                bitmap = face.glyph.bitmap
                left = face.glyph.bitmap_left
                top = face.glyph.bitmap_top
                width = bitmap.width
                rows = bitmap.rows
                pitch = bitmap.pitch
    
                offset_x = left
                offset_y = glyph_height - (top - glyph_descender)
    
                # '#' in the smallest font generates a larger glyph than the "fixed" font width.
                if offset_x + width > glyph_width:
                    offset_x = glyph_width - width
                    if offset_x < 0:
                        width += offset_x
                        offset_x = 0
    
                base_x += offset_x
                base_y += offset_y
    
                assert (offset_x + width <= glyph_width)
                assert (offset_y + rows <= glyph_height)
    
                # Write the character bitmap in the font image.
                for y in range(rows):
                    for x in range(width):
                        pixel_value = bitmap.buffer[y * pitch + x]
                        output_bit = 1 if pixel_value >= 122 else 0
    
                        font_array_row = base_y + y
                        font_array_col = (base_x + x) // 32
                        font_array_bit = (base_x + x) % 32
                        font_array[font_array_row][font_array_col] |= output_bit << font_array_bit
    
            # Output the image to a C array.
            data = 'constexpr uint32_t ' + font_array_name + '[' + font_height + '][' + font_width + '/32] = {\n'
            for y in range(font_array_height):
                data += '{'
                for x in range(font_array_width):
                    data += '0x{:08X}, '.format(font_array[y][x])
                data += '},\n'
            data += '};\n'
    
            font_glyph_widths.append(glyph_width)
            font_glyph_heights.append(glyph_height)
            font_layers.append('constexpr int ' + font_layer_symbol + ' = ' + font_layer + ';')
            font_data.append(data)
            get_font_layer_pixel.append(
                template_get_font_layer_pixel.format(
                    layer=font_layer_symbol, font_image=font_array_name))
            current_font_layer += 1
    
        with open(out_file_h, 'w') as outfile:
            outfile.write(
                template_out_file_h.format(
                    script_name=__file__,
                    font_file=font_file,
                    out_file_name=out_file_h,
                    font_count=len(font_data),
                    font_glyph_widths=','.join(map(str, font_glyph_widths)),
                    font_glyph_heights=','.join(map(str, font_glyph_heights)),
                    max_font_width=max(font_glyph_widths),
                    max_font_height=max(font_glyph_heights),
                    font_layers='\n'.join(font_layers)))
            outfile.close()
    
        font_layer_widths = [
            'kFontGlyphWidths[' + str(layer) + '] * kFontCharactersPerRow'
            for layer in range(len(font_data))
        ]
        font_layer_heights = [
            'kFontGlyphHeights[' + str(layer) + '] * kFontCharactersPerCol'
            for layer in range(len(font_data))
        ]
    
        with open(out_file_cpp, 'w') as outfile:
            outfile.write(
                template_out_file_cpp.format(
                    script_name=__file__,
                    font_file=font_file,
                    out_file_name=out_file_cpp,
                    font_layer_widths=','.join(font_layer_widths),
                    font_layer_heights=','.join(font_layer_heights),
                    font_data='\n'.join(font_data),
                    get_font_layer_pixel=''.join(get_font_layer_pixel)))
            outfile.close()
    
    
    if __name__ == '__main__':
        sys.exit(main())