• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env vpython3
2#
3# [VPYTHON:BEGIN]
4# wheel: <
5#   name: "infra/python/wheels/freetype-py/${vpython_platform}"
6#   version: "version:2.2.0.chromium.4"
7# >
8# [VPYTHON:END]
9
10# Copyright 2019 The ANGLE Project Authors. All rights reserved.
11# Use of this source code is governed by a BSD-style license that can be
12# found in the LICENSE file.
13#
14# gen_vk_overlay_fonts.py:
15#  Code generation for overlay fonts.  Should be run if the font file under overlay/ is changed,
16#  or the font sizes declared in this file are modified.  The font is assumed to be monospace.
17#  The output will contain ASCII characters in order from ' ' to '~'.  The output will be images
18#  with 95 layers, with each smaller font size having half the size of the previous to form a mip
19#  chain.
20#  NOTE: don't run this script directly. Run scripts/run_code_generation.py.
21
22import sys
23
24if len(sys.argv) < 2:
25    from freetype import *
26
27out_file_cpp = 'Overlay_font_autogen.cpp'
28out_file_h = 'Overlay_font_autogen.h'
29font_file = 'overlay/DejaVuSansMono-Bold.ttf'
30
31template_out_file_h = u"""// GENERATED FILE - DO NOT EDIT.
32// Generated by {script_name} using {font_file}.
33//
34// Copyright 2022 The ANGLE Project Authors. All rights reserved.
35// Use of this source code is governed by a BSD-style license that can be
36// found in the LICENSE file.
37//
38// {out_file_name}:
39//   Autogenerated overlay font data.
40
41#include "libANGLE/Overlay.h"
42
43namespace gl
44{{
45namespace overlay
46{{
47constexpr uint32_t kFontMipCount = {font_count};
48constexpr uint32_t kFontCharacters = {char_count};
49constexpr uint32_t kFontGlyphWidth = {max_font_width};
50constexpr uint32_t kFontGlyphHeight = {max_font_height};
51constexpr uint32_t kFontMipDataSize[kFontMipCount] = {{{font_mip_data_sizes}}};
52constexpr uint32_t kFontMipDataOffset[kFontMipCount] = {{{font_mip_data_offsets}}};
53constexpr uint32_t kFontTotalDataSize = {total_font_data_size};
54{font_mips}
55}}  // namespace overlay
56}}  // namespace gl
57
58"""
59
60template_out_file_cpp = u"""// GENERATED FILE - DO NOT EDIT.
61// Generated by {script_name} using images from {font_file}.
62//
63// Copyright 2022 The ANGLE Project Authors. All rights reserved.
64// Use of this source code is governed by a BSD-style license that can be
65// found in the LICENSE file.
66//
67// {out_file_name}:
68//   Autogenerated overlay font data.
69
70#include "libANGLE/Overlay.h"
71#include "libANGLE/Overlay_font_autogen.h"
72
73#include <numeric>
74
75namespace gl
76{{
77using namespace overlay;
78
79// Save binary size if the font images are never to be used.
80#if ANGLE_ENABLE_OVERLAY
81namespace
82{{
83constexpr uint8_t kFontData[{total_font_data_size}] = {{
84// clang-format off
85{all_font_data}
86// clang-format on
87}};
88}}  // anonymous namespace
89
90const uint8_t *OverlayState::getFontData() const
91{{
92    return kFontData;
93}}
94#else
95const uint8_t *OverlayState::getFontData() const
96{{
97    return nullptr;
98}}
99#endif
100}}  // namespace gl
101"""
102
103
104def main():
105    if len(sys.argv) == 2 and sys.argv[1] == 'inputs':
106        # disabled because of issues on Windows. http://anglebug.com/3892
107        # print(font_file)
108        return
109    if len(sys.argv) == 2 and sys.argv[1] == 'outputs':
110        print(','.join([out_file_cpp, out_file_h]))
111        return
112
113    # Font sizes are chosen such that the sizes form a mip chain.
114    font_defs = [('large', 29), ('small', 14)]
115    chars = ' !"#$%&\'()*+,-./0123456789:;<=>?' + \
116            '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + \
117            '`abcdefghijklmnopqrstuvwxyz{|}~'
118    char_count = len(chars)
119
120    font_glyph_widths = []
121    font_glyph_heights = []
122    font_data = ""
123    font_mips = []
124    current_font_mip = 0
125    font_data_sizes = []
126    font_data_offsets = []
127    total_font_data_size = 0
128
129    # Load the font file.
130    face = Face(font_file)
131    assert (face.is_fixed_width)
132
133    for font_name, font_size in font_defs:
134
135        # Since the font is fixed width, we can retrieve its size right away.
136        face.set_char_size(font_size << 6)
137        glyph_width = face.size.max_advance >> 6
138        glyph_ascender = face.size.ascender >> 6
139        glyph_descender = face.size.descender >> 6
140        glyph_height = glyph_ascender - glyph_descender
141        font_glyph_widths.append(glyph_width)
142        font_glyph_heights.append(glyph_height)
143
144        # Make sure the fonts form a mipchain
145        if current_font_mip > 0:
146            assert (glyph_width == font_glyph_widths[current_font_mip - 1] // 2)
147            assert (glyph_height == font_glyph_heights[current_font_mip - 1] // 2)
148
149        font_tag = font_name.capitalize()
150        font_mip = str(current_font_mip)
151        font_mip_symbol = 'kFontMip' + font_tag
152
153        font_data += '// ' + font_tag + '\n'
154
155        # Font pixels are packed in 32-bit values.
156        font_data_size = char_count * glyph_width * glyph_height
157        font_data_sizes.append(font_data_size)
158        font_data_offsets.append(total_font_data_size)
159        total_font_data_size += font_data_size
160
161        for charIndex in range(char_count):
162            char = chars[charIndex]
163            font_data += "// '" + char + "'\n"
164
165            # Render the character.
166            face.load_char(char)
167            bitmap = face.glyph.bitmap
168            left = face.glyph.bitmap_left
169            top = face.glyph.bitmap_top
170            width = bitmap.width
171            rows = bitmap.rows
172            pitch = bitmap.pitch
173
174            offset_x = left
175            offset_y = glyph_height - (top - glyph_descender)
176
177            # Some glyphs like '#', '&' etc generate a larger glyph than the "fixed" font width.
178            if offset_x + width > glyph_width:
179                offset_x = glyph_width - width
180                if offset_x < 0:
181                    width += offset_x
182                    offset_x = 0
183
184            assert (offset_x + width <= glyph_width)
185            assert (offset_y + rows <= glyph_height)
186
187            # Write the character bitmap in the font image.
188            for y in range(glyph_height):
189                for x in range(glyph_width):
190                    if y < offset_y or y >= offset_y + rows or x < offset_x or x >= offset_x + width:
191                        font_data += '   0,'
192                    else:
193                        pixel_value = bitmap.buffer[(y - offset_y) * pitch + (x - offset_x)]
194                        if pixel_value == 0:
195                            font_data += '   0,'
196                        else:
197                            font_data += '0x{:02X},'.format(pixel_value)
198                font_data += '\n'
199
200        font_mips.append('constexpr uint32_t ' + font_mip_symbol + ' = ' + font_mip + ';')
201        current_font_mip += 1
202
203    with open(out_file_h, 'w') as outfile:
204        outfile.write(
205            template_out_file_h.format(
206                script_name=__file__,
207                font_file=font_file,
208                out_file_name=out_file_h,
209                font_count=len(font_defs),
210                char_count=char_count,
211                max_font_width=font_glyph_widths[0],
212                max_font_height=font_glyph_heights[0],
213                font_mip_data_sizes=','.join([str(s) for s in font_data_sizes]),
214                font_mip_data_offsets=','.join([str(s) for s in font_data_offsets]),
215                total_font_data_size=total_font_data_size,
216                font_mips='\n'.join(font_mips)))
217        outfile.close()
218
219    with open(out_file_cpp, 'w') as outfile:
220        outfile.write(
221            template_out_file_cpp.format(
222                script_name=__file__,
223                font_file=font_file,
224                out_file_name=out_file_cpp,
225                total_font_data_size=total_font_data_size,
226                all_font_data=font_data))
227        outfile.close()
228
229
230if __name__ == '__main__':
231    sys.exit(main())
232