| #!/usr/bin/env vpython3 |
| # |
| # [VPYTHON:BEGIN] |
| # wheel: < |
| # name: "infra/python/wheels/freetype-py/${vpython_platform}" |
| # version: "version:2.2.0.chromium.4" |
| # > |
| # [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 95 layers, with each smaller font size having half the size of the previous to form a mip |
| # chain. |
| # 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 2022 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 uint32_t kFontMipCount = {font_count}; |
| constexpr uint32_t kFontCharacters = {char_count}; |
| constexpr uint32_t kFontGlyphWidth = {max_font_width}; |
| constexpr uint32_t kFontGlyphHeight = {max_font_height}; |
| constexpr uint32_t kFontMipDataSize[kFontMipCount] = {{{font_mip_data_sizes}}}; |
| constexpr uint32_t kFontMipDataOffset[kFontMipCount] = {{{font_mip_data_offsets}}}; |
| constexpr uint32_t kFontTotalDataSize = {total_font_data_size}; |
| {font_mips} |
| }} // namespace overlay |
| }} // namespace gl |
| |
| """ |
| |
| template_out_file_cpp = u"""// GENERATED FILE - DO NOT EDIT. |
| // Generated by {script_name} using images from {font_file}. |
| // |
| // Copyright 2022 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 uint8_t kFontData[{total_font_data_size}] = {{ |
| // clang-format off |
| {all_font_data} |
| // clang-format on |
| }}; |
| }} // anonymous namespace |
| |
| const uint8_t *OverlayState::getFontData() const |
| {{ |
| return kFontData; |
| }} |
| #else |
| const uint8_t *OverlayState::getFontData() const |
| {{ |
| return nullptr; |
| }} |
| #endif |
| }} // namespace gl |
| """ |
| |
| |
| 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 sizes are chosen such that the sizes form a mip chain. |
| font_defs = [('large', 29), ('small', 14)] |
| chars = ' !"#$%&\'()*+,-./0123456789:;<=>?' + \ |
| '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + \ |
| '`abcdefghijklmnopqrstuvwxyz{|}~' |
| char_count = len(chars) |
| |
| font_glyph_widths = [] |
| font_glyph_heights = [] |
| font_data = "" |
| font_mips = [] |
| current_font_mip = 0 |
| font_data_sizes = [] |
| font_data_offsets = [] |
| total_font_data_size = 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_glyph_widths.append(glyph_width) |
| font_glyph_heights.append(glyph_height) |
| |
| # Make sure the fonts form a mipchain |
| if current_font_mip > 0: |
| assert (glyph_width == font_glyph_widths[current_font_mip - 1] // 2) |
| assert (glyph_height == font_glyph_heights[current_font_mip - 1] // 2) |
| |
| font_tag = font_name.capitalize() |
| font_mip = str(current_font_mip) |
| font_mip_symbol = 'kFontMip' + font_tag |
| |
| font_data += '// ' + font_tag + '\n' |
| |
| # Font pixels are packed in 32-bit values. |
| font_data_size = char_count * glyph_width * glyph_height |
| font_data_sizes.append(font_data_size) |
| font_data_offsets.append(total_font_data_size) |
| total_font_data_size += font_data_size |
| |
| for charIndex in range(char_count): |
| char = chars[charIndex] |
| font_data += "// '" + char + "'\n" |
| |
| # 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) |
| |
| # Some glyphs like '#', '&' etc generate 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 |
| |
| assert (offset_x + width <= glyph_width) |
| assert (offset_y + rows <= glyph_height) |
| |
| # Write the character bitmap in the font image. |
| for y in range(glyph_height): |
| for x in range(glyph_width): |
| if y < offset_y or y >= offset_y + rows or x < offset_x or x >= offset_x + width: |
| font_data += ' 0,' |
| else: |
| pixel_value = bitmap.buffer[(y - offset_y) * pitch + (x - offset_x)] |
| if pixel_value == 0: |
| font_data += ' 0,' |
| else: |
| font_data += '0x{:02X},'.format(pixel_value) |
| font_data += '\n' |
| |
| font_mips.append('constexpr uint32_t ' + font_mip_symbol + ' = ' + font_mip + ';') |
| current_font_mip += 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_defs), |
| char_count=char_count, |
| max_font_width=font_glyph_widths[0], |
| max_font_height=font_glyph_heights[0], |
| font_mip_data_sizes=','.join([str(s) for s in font_data_sizes]), |
| font_mip_data_offsets=','.join([str(s) for s in font_data_offsets]), |
| total_font_data_size=total_font_data_size, |
| font_mips='\n'.join(font_mips))) |
| outfile.close() |
| |
| 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, |
| total_font_data_size=total_font_data_size, |
| all_font_data=font_data)) |
| outfile.close() |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |