#!/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 # Conditional import enables getting inputs/outputs with python3 instead of vpython3 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/RobotoMono-Bold.ttf' font_license = u"""// Font copyright Google: // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License.""" 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. // {font_license} // // {out_file_name}: // Autogenerated overlay font data. #include "libANGLE/Overlay.h" #include "libANGLE/Overlay_font_autogen.h" #include 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/42262538 # 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=os.path.basename(__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=os.path.basename(__file__), font_file=font_file, font_license=font_license, 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())