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