#!/usr/bin/env vpython # # [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. from datetime import date 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 {copyright_year} 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 {copyright_year} 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 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 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({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, copyright_year=date.today().year, 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, copyright_year=date.today().year, 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())