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 24# Conditional import enables getting inputs/outputs with python3 instead of vpython3 25if len(sys.argv) < 2: 26 from freetype import * 27 28out_file_cpp = 'Overlay_font_autogen.cpp' 29out_file_h = 'Overlay_font_autogen.h' 30font_file = 'overlay/RobotoMono-Bold.ttf' 31font_license = u"""// Font copyright Google: 32// 33// Licensed under the Apache License, Version 2.0 (the "License"); 34// you may not use this file except in compliance with the License. 35// You may obtain a copy of the License at 36// 37// http://www.apache.org/licenses/LICENSE-2.0 38// 39// Unless required by applicable law or agreed to in writing, software 40// distributed under the License is distributed on an "AS IS" BASIS, 41// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 42// See the License for the specific language governing permissions and 43// limitations under the License.""" 44 45template_out_file_h = u"""// GENERATED FILE - DO NOT EDIT. 46// Generated by {script_name} using {font_file}. 47// 48// Copyright 2022 The ANGLE Project Authors. All rights reserved. 49// Use of this source code is governed by a BSD-style license that can be 50// found in the LICENSE file. 51// 52// {out_file_name}: 53// Autogenerated overlay font data. 54 55#include "libANGLE/Overlay.h" 56 57namespace gl 58{{ 59namespace overlay 60{{ 61constexpr uint32_t kFontMipCount = {font_count}; 62constexpr uint32_t kFontCharacters = {char_count}; 63constexpr uint32_t kFontGlyphWidth = {max_font_width}; 64constexpr uint32_t kFontGlyphHeight = {max_font_height}; 65constexpr uint32_t kFontMipDataSize[kFontMipCount] = {{{font_mip_data_sizes}}}; 66constexpr uint32_t kFontMipDataOffset[kFontMipCount] = {{{font_mip_data_offsets}}}; 67constexpr uint32_t kFontTotalDataSize = {total_font_data_size}; 68{font_mips} 69}} // namespace overlay 70}} // namespace gl 71 72""" 73 74template_out_file_cpp = u"""// GENERATED FILE - DO NOT EDIT. 75// Generated by {script_name} using images from {font_file}. 76// 77// Copyright 2022 The ANGLE Project Authors. All rights reserved. 78// Use of this source code is governed by a BSD-style license that can be 79// found in the LICENSE file. 80// 81{font_license} 82// 83// {out_file_name}: 84// Autogenerated overlay font data. 85 86#include "libANGLE/Overlay.h" 87#include "libANGLE/Overlay_font_autogen.h" 88 89#include <numeric> 90 91namespace gl 92{{ 93using namespace overlay; 94 95// Save binary size if the font images are never to be used. 96#if ANGLE_ENABLE_OVERLAY 97namespace 98{{ 99constexpr uint8_t kFontData[{total_font_data_size}] = {{ 100// clang-format off 101{all_font_data} 102// clang-format on 103}}; 104}} // anonymous namespace 105 106const uint8_t *OverlayState::getFontData() const 107{{ 108 return kFontData; 109}} 110#else 111const uint8_t *OverlayState::getFontData() const 112{{ 113 return nullptr; 114}} 115#endif 116}} // namespace gl 117""" 118 119 120def main(): 121 if len(sys.argv) == 2 and sys.argv[1] == 'inputs': 122 # disabled because of issues on Windows. http://anglebug.com/42262538 123 # print(font_file) 124 return 125 if len(sys.argv) == 2 and sys.argv[1] == 'outputs': 126 print(','.join([out_file_cpp, out_file_h])) 127 return 128 129 # Font sizes are chosen such that the sizes form a mip chain. 130 font_defs = [('large', 29), ('small', 14)] 131 chars = ' !"#$%&\'()*+,-./0123456789:;<=>?' + \ 132 '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_' + \ 133 '`abcdefghijklmnopqrstuvwxyz{|}~' 134 char_count = len(chars) 135 136 font_glyph_widths = [] 137 font_glyph_heights = [] 138 font_data = "" 139 font_mips = [] 140 current_font_mip = 0 141 font_data_sizes = [] 142 font_data_offsets = [] 143 total_font_data_size = 0 144 145 # Load the font file. 146 face = Face(font_file) 147 assert (face.is_fixed_width) 148 149 for font_name, font_size in font_defs: 150 151 # Since the font is fixed width, we can retrieve its size right away. 152 face.set_char_size(font_size << 6) 153 glyph_width = face.size.max_advance >> 6 154 glyph_ascender = face.size.ascender >> 6 155 glyph_descender = face.size.descender >> 6 156 glyph_height = glyph_ascender - glyph_descender 157 font_glyph_widths.append(glyph_width) 158 font_glyph_heights.append(glyph_height) 159 160 # Make sure the fonts form a mipchain 161 if current_font_mip > 0: 162 assert (glyph_width == font_glyph_widths[current_font_mip - 1] // 2) 163 assert (glyph_height == font_glyph_heights[current_font_mip - 1] // 2) 164 165 font_tag = font_name.capitalize() 166 font_mip = str(current_font_mip) 167 font_mip_symbol = 'kFontMip' + font_tag 168 169 font_data += '// ' + font_tag + '\n' 170 171 # Font pixels are packed in 32-bit values. 172 font_data_size = char_count * glyph_width * glyph_height 173 font_data_sizes.append(font_data_size) 174 font_data_offsets.append(total_font_data_size) 175 total_font_data_size += font_data_size 176 177 for charIndex in range(char_count): 178 char = chars[charIndex] 179 font_data += "// '" + char + "'\n" 180 181 # Render the character. 182 face.load_char(char) 183 bitmap = face.glyph.bitmap 184 left = face.glyph.bitmap_left 185 top = face.glyph.bitmap_top 186 width = bitmap.width 187 rows = bitmap.rows 188 pitch = bitmap.pitch 189 190 offset_x = left 191 offset_y = glyph_height - (top - glyph_descender) 192 193 # Some glyphs like '#', '&' etc generate a larger glyph than the "fixed" font width. 194 if offset_x + width > glyph_width: 195 offset_x = glyph_width - width 196 if offset_x < 0: 197 width += offset_x 198 offset_x = 0 199 200 assert (offset_x + width <= glyph_width) 201 assert (offset_y + rows <= glyph_height) 202 203 # Write the character bitmap in the font image. 204 for y in range(glyph_height): 205 for x in range(glyph_width): 206 if y < offset_y or y >= offset_y + rows or x < offset_x or x >= offset_x + width: 207 font_data += ' 0,' 208 else: 209 pixel_value = bitmap.buffer[(y - offset_y) * pitch + (x - offset_x)] 210 if pixel_value == 0: 211 font_data += ' 0,' 212 else: 213 font_data += '0x{:02X},'.format(pixel_value) 214 font_data += '\n' 215 216 font_mips.append('constexpr uint32_t ' + font_mip_symbol + ' = ' + font_mip + ';') 217 current_font_mip += 1 218 219 with open(out_file_h, 'w') as outfile: 220 outfile.write( 221 template_out_file_h.format( 222 script_name=os.path.basename(__file__), 223 font_file=font_file, 224 out_file_name=out_file_h, 225 font_count=len(font_defs), 226 char_count=char_count, 227 max_font_width=font_glyph_widths[0], 228 max_font_height=font_glyph_heights[0], 229 font_mip_data_sizes=','.join([str(s) for s in font_data_sizes]), 230 font_mip_data_offsets=','.join([str(s) for s in font_data_offsets]), 231 total_font_data_size=total_font_data_size, 232 font_mips='\n'.join(font_mips))) 233 outfile.close() 234 235 with open(out_file_cpp, 'w') as outfile: 236 outfile.write( 237 template_out_file_cpp.format( 238 script_name=os.path.basename(__file__), 239 font_file=font_file, 240 font_license=font_license, 241 out_file_name=out_file_cpp, 242 total_font_data_size=total_font_data_size, 243 all_font_data=font_data)) 244 outfile.close() 245 246 247if __name__ == '__main__': 248 sys.exit(main()) 249