• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env vpython
2#
3# [VPYTHON:BEGIN]
4# wheel: <
5#   name: "infra/python/wheels/freetype-py/${vpython_platform}"
6#   version: "version:2.1.0.post1"
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 3 rows of 32 characters each.
19#  NOTE: don't run this script directly. Run scripts/run_code_generation.py.
20
21from datetime import date
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 {copyright_year} 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 int kFontCount = {font_count};
48constexpr int kFontGlyphWidths[kFontCount] = {{ {font_glyph_widths} }};
49constexpr int kFontGlyphHeights[kFontCount] = {{ {font_glyph_heights} }};
50constexpr int kFontCharactersPerRow = 32;
51constexpr int kFontCharactersPerCol = 3;
52constexpr int kFontCharacters = kFontCharactersPerRow * kFontCharactersPerCol;
53constexpr int kFontImageWidth = {max_font_width} * kFontCharactersPerRow;
54constexpr int kFontImageHeight = {max_font_height} * kFontCharactersPerCol;
55{font_layers}
56}}  // namespace overlay
57}}  // namespace gl
58
59"""
60
61template_out_file_cpp = u"""// GENERATED FILE - DO NOT EDIT.
62// Generated by {script_name} using images from {font_file}.
63//
64// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved.
65// Use of this source code is governed by a BSD-style license that can be
66// found in the LICENSE file.
67//
68// {out_file_name}:
69//   Autogenerated overlay font data.
70
71#include "libANGLE/Overlay.h"
72#include "libANGLE/Overlay_font_autogen.h"
73
74#include <numeric>
75
76namespace gl
77{{
78using namespace overlay;
79
80// Save binary size if the font images are never to be used.
81#if ANGLE_ENABLE_OVERLAY
82namespace
83{{
84constexpr int kFontWidths[kFontCount] = {{ {font_layer_widths} }};
85constexpr int kFontHeights[kFontCount] = {{ {font_layer_heights} }};
86
87{font_data}
88
89// Returns a bit with the value of the pixel.
90template<int kFontWidth, int kFontHeight>
91uint32_t GetFontLayerPixel(const uint32_t fontImage[kFontHeight][kFontWidth / 32], int x, int y)
92{{
93    ASSERT(x >= 0 && x < kFontWidth && y >= 0 && y < kFontHeight);
94    return fontImage[y][x / 32] >> (x % 32) & 1;
95}}
96
97inline uint32_t GetFontPixel(int layer, int x, int y)
98{{
99    switch (layer)
100    {{
101    {get_font_layer_pixel}
102    default:
103        UNREACHABLE();
104        return 0;
105    }}
106}}
107
108}}  // anonymous namespace
109
110void OverlayState::initFontData(uint8_t *fontData) const
111{{
112    constexpr int kFontDataLayerSize = kFontImageWidth * kFontImageHeight;
113
114    // Unpack the font bitmap into R8_UNORM format.  Border pixels are given a 0.5 value for better
115    // font visibility.
116    for (int layer = 0; layer < kFontCount; ++layer)
117    {{
118        memset(fontData, 0, kFontDataLayerSize);
119        for (int y = 0; y < kFontHeights[layer]; ++y)
120        {{
121            for (int x = 0; x < kFontWidths[layer]; ++x)
122            {{
123                uint32_t src     = GetFontPixel(layer, x, y);
124                uint8_t dstValue = src ? 255 : 0;
125                fontData[y * kFontImageWidth + x] = dstValue;
126            }}
127        }}
128        fontData += kFontDataLayerSize;
129    }}
130}}
131#else
132void OverlayState::initFontData(uint8_t *fontData) const
133{{
134    memset(fontData, 0, kFontCount * kFontImageWidth * kFontImageHeight * sizeof(*fontData));
135}}
136#endif
137}}  // namespace gl
138"""
139
140template_get_font_layer_pixel = u"""case {layer}:
141    return GetFontLayerPixel<kFontWidths[{layer}], kFontHeights[{layer}]>({font_image}, x, y);
142"""
143
144
145def main():
146    if len(sys.argv) == 2 and sys.argv[1] == 'inputs':
147        # disabled because of issues on Windows. http://anglebug.com/3892
148        # print(font_file)
149        return
150    if len(sys.argv) == 2 and sys.argv[1] == 'outputs':
151        print(','.join([out_file_cpp, out_file_h]))
152        return
153
154    font_defs = [('large', 36), ('medium', 23), ('small', 14)]
155    chars = ' !"#$%&\'()*+,-./0123456789:;<=>?' + \
156            '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + \
157            '`abcdefghijklmnopqrstuvwxyz{|}~ '
158    output_rows = 3
159    output_cols = 32
160    assert (len(chars) == output_rows * output_cols)
161
162    font_glyph_widths = []
163    font_glyph_heights = []
164    font_layers = []
165    font_data = []
166    get_font_layer_pixel = []
167    current_font_layer = 0
168
169    # Load the font file.
170    face = Face(font_file)
171    assert (face.is_fixed_width)
172
173    for font_name, font_size in font_defs:
174
175        # Since the font is fixed width, we can retrieve its size right away.
176        face.set_char_size(font_size << 6)
177        glyph_width = face.size.max_advance >> 6
178        glyph_ascender = face.size.ascender >> 6
179        glyph_descender = face.size.descender >> 6
180        glyph_height = glyph_ascender - glyph_descender
181
182        font_tag = font_name.capitalize()
183        font_layer = str(current_font_layer)
184        font_layer_symbol = 'kFontLayer' + font_tag
185        font_array_name = 'kFontImage' + font_tag
186        font_width = 'kFontWidths[' + font_layer_symbol + ']'
187        font_height = 'kFontHeights[' + font_layer_symbol + ']'
188
189        # Font pixels are packed in 32-bit values.
190        font_array_width = output_cols * glyph_width / 32
191        font_array_height = output_rows * glyph_height
192        font_array = [[0] * font_array_width for i in range(font_array_height)]
193
194        for charIndex in range(len(chars)):
195            char = chars[charIndex]
196            base_x = (charIndex % output_cols) * glyph_width
197            base_y = (charIndex / output_cols) * glyph_height
198
199            # Render the character.
200            face.load_char(char)
201            bitmap = face.glyph.bitmap
202            left = face.glyph.bitmap_left
203            top = face.glyph.bitmap_top
204            width = bitmap.width
205            rows = bitmap.rows
206            pitch = bitmap.pitch
207
208            offset_x = left
209            offset_y = glyph_height - (top - glyph_descender)
210
211            # '#' in the smallest font generates a larger glyph than the "fixed" font width.
212            if offset_x + width > glyph_width:
213                offset_x = glyph_width - width
214                if offset_x < 0:
215                    width += offset_x
216                    offset_x = 0
217
218            base_x += offset_x
219            base_y += offset_y
220
221            assert (offset_x + width <= glyph_width)
222            assert (offset_y + rows <= glyph_height)
223
224            # Write the character bitmap in the font image.
225            for y in range(rows):
226                for x in range(width):
227                    pixel_value = bitmap.buffer[y * pitch + x]
228                    output_bit = 1 if pixel_value >= 122 else 0
229
230                    font_array_row = base_y + y
231                    font_array_col = (base_x + x) / 32
232                    font_array_bit = (base_x + x) % 32
233                    font_array[font_array_row][font_array_col] |= output_bit << font_array_bit
234
235        # Output the image to a C array.
236        data = 'constexpr uint32_t ' + font_array_name + '[' + font_height + '][' + font_width + '/32] = {\n'
237        for y in range(font_array_height):
238            data += '{'
239            for x in range(font_array_width):
240                data += '0x{:08X}, '.format(font_array[y][x])
241            data += '},\n'
242        data += '};\n'
243
244        font_glyph_widths.append(glyph_width)
245        font_glyph_heights.append(glyph_height)
246        font_layers.append('constexpr int ' + font_layer_symbol + ' = ' + font_layer + ';')
247        font_data.append(data)
248        get_font_layer_pixel.append(
249            template_get_font_layer_pixel.format(
250                layer=font_layer_symbol, font_image=font_array_name))
251        current_font_layer += 1
252
253    with open(out_file_h, 'w') as outfile:
254        outfile.write(
255            template_out_file_h.format(
256                script_name=__file__,
257                font_file=font_file,
258                copyright_year=date.today().year,
259                out_file_name=out_file_h,
260                font_count=len(font_data),
261                font_glyph_widths=','.join(map(str, font_glyph_widths)),
262                font_glyph_heights=','.join(map(str, font_glyph_heights)),
263                max_font_width=max(font_glyph_widths),
264                max_font_height=max(font_glyph_heights),
265                font_layers='\n'.join(font_layers)))
266        outfile.close()
267
268    font_layer_widths = [
269        'kFontGlyphWidths[' + str(layer) + '] * kFontCharactersPerRow'
270        for layer in range(len(font_data))
271    ]
272    font_layer_heights = [
273        'kFontGlyphHeights[' + str(layer) + '] * kFontCharactersPerCol'
274        for layer in range(len(font_data))
275    ]
276
277    with open(out_file_cpp, 'w') as outfile:
278        outfile.write(
279            template_out_file_cpp.format(
280                script_name=__file__,
281                font_file=font_file,
282                copyright_year=date.today().year,
283                out_file_name=out_file_cpp,
284                font_layer_widths=','.join(font_layer_widths),
285                font_layer_heights=','.join(font_layer_heights),
286                font_data='\n'.join(font_data),
287                get_font_layer_pixel=''.join(get_font_layer_pixel)))
288        outfile.close()
289
290
291if __name__ == '__main__':
292    sys.exit(main())
293