| #!/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 <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, |
| 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()) |