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