blob: 22a99de3f9466e35c5eab1a5dcd979743556293c [file] [log] [blame]
#!/usr/bin/env vpython
#
# [VPYTHON:BEGIN]
# wheel: <
# name: "infra/python/wheels/freetype-py/${vpython_platform}"
# version: "version:2.1.0.post1"
# >
# [VPYTHON:END]
# Copyright 2019 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# gen_vk_overlay_fonts.py:
# Code generation for overlay fonts. Should be run if the font file under overlay/ is changed,
# or the font sizes declared in this file are modified. The font is assumed to be monospace.
# The output will contain ASCII characters in order from ' ' to '~'. The output will be images
# with 3 rows of 32 characters each.
# NOTE: don't run this script directly. Run scripts/run_code_generation.py.
from datetime import date
import sys
if len(sys.argv) < 2:
from freetype import *
out_file_cpp = 'Overlay_font_autogen.cpp'
out_file_h = 'Overlay_font_autogen.h'
font_file = 'overlay/DejaVuSansMono-Bold.ttf'
template_out_file_h = u"""// GENERATED FILE - DO NOT EDIT.
// Generated by {script_name} using {font_file}.
//
// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// {out_file_name}:
// Autogenerated overlay font data.
#include "libANGLE/Overlay.h"
namespace gl
{{
namespace overlay
{{
constexpr int kFontCount = {font_count};
constexpr int kFontGlyphWidths[kFontCount] = {{ {font_glyph_widths} }};
constexpr int kFontGlyphHeights[kFontCount] = {{ {font_glyph_heights} }};
constexpr int kFontCharactersPerRow = 32;
constexpr int kFontCharactersPerCol = 3;
constexpr int kFontCharacters = kFontCharactersPerRow * kFontCharactersPerCol;
constexpr int kFontImageWidth = {max_font_width} * kFontCharactersPerRow;
constexpr int kFontImageHeight = {max_font_height} * kFontCharactersPerCol;
{font_layers}
}} // namespace overlay
}} // namespace gl
"""
template_out_file_cpp = u"""// GENERATED FILE - DO NOT EDIT.
// Generated by {script_name} using images from {font_file}.
//
// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// {out_file_name}:
// Autogenerated overlay font data.
#include "libANGLE/Overlay.h"
#include "libANGLE/Overlay_font_autogen.h"
#include <numeric>
namespace gl
{{
using namespace overlay;
// Save binary size if the font images are never to be used.
#if ANGLE_ENABLE_OVERLAY
namespace
{{
constexpr int kFontWidths[kFontCount] = {{ {font_layer_widths} }};
constexpr int kFontHeights[kFontCount] = {{ {font_layer_heights} }};
{font_data}
// Returns a bit with the value of the pixel.
template<int kFontWidth, int kFontHeight>
uint32_t GetFontLayerPixel(const uint32_t fontImage[kFontHeight][kFontWidth / 32], int x, int y)
{{
ASSERT(x >= 0 && x < kFontWidth && y >= 0 && y < kFontHeight);
return fontImage[y][x / 32] >> (x % 32) & 1;
}}
inline uint32_t GetFontPixel(int layer, int x, int y)
{{
switch (layer)
{{
{get_font_layer_pixel}
default:
UNREACHABLE();
return 0;
}}
}}
}} // anonymous namespace
void OverlayState::initFontData(uint8_t *fontData) const
{{
constexpr int kFontDataLayerSize = kFontImageWidth * kFontImageHeight;
// Unpack the font bitmap into R8_UNORM format. Border pixels are given a 0.5 value for better
// font visibility.
for (int layer = 0; layer < kFontCount; ++layer)
{{
memset(fontData, 0, kFontDataLayerSize);
for (int y = 0; y < kFontHeights[layer]; ++y)
{{
for (int x = 0; x < kFontWidths[layer]; ++x)
{{
uint32_t src = GetFontPixel(layer, x, y);
uint8_t dstValue = src ? 255 : 0;
fontData[y * kFontImageWidth + x] = dstValue;
}}
}}
fontData += kFontDataLayerSize;
}}
}}
#else
void OverlayState::initFontData(uint8_t *fontData) const
{{
memset(fontData, 0, kFontCount * kFontImageWidth * kFontImageHeight * sizeof(*fontData));
}}
#endif
}} // namespace gl
"""
template_get_font_layer_pixel = u"""case {layer}:
return GetFontLayerPixel<kFontWidths[{layer}], kFontHeights[{layer}]>({font_image}, x, y);
"""
def main():
if len(sys.argv) == 2 and sys.argv[1] == 'inputs':
# disabled because of issues on Windows. http://anglebug.com/3892
# print(font_file)
return
if len(sys.argv) == 2 and sys.argv[1] == 'outputs':
print(','.join([out_file_cpp, out_file_h]))
return
font_defs = [('large', 36), ('medium', 23), ('small', 14)]
chars = ' !"#$%&\'()*+,-./0123456789:;<=>?' + \
'@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + \
'`abcdefghijklmnopqrstuvwxyz{|}~ '
output_rows = 3
output_cols = 32
assert (len(chars) == output_rows * output_cols)
font_glyph_widths = []
font_glyph_heights = []
font_layers = []
font_data = []
get_font_layer_pixel = []
current_font_layer = 0
# Load the font file.
face = Face(font_file)
assert (face.is_fixed_width)
for font_name, font_size in font_defs:
# Since the font is fixed width, we can retrieve its size right away.
face.set_char_size(font_size << 6)
glyph_width = face.size.max_advance >> 6
glyph_ascender = face.size.ascender >> 6
glyph_descender = face.size.descender >> 6
glyph_height = glyph_ascender - glyph_descender
font_tag = font_name.capitalize()
font_layer = str(current_font_layer)
font_layer_symbol = 'kFontLayer' + font_tag
font_array_name = 'kFontImage' + font_tag
font_width = 'kFontWidths[' + font_layer_symbol + ']'
font_height = 'kFontHeights[' + font_layer_symbol + ']'
# Font pixels are packed in 32-bit values.
font_array_width = output_cols * glyph_width / 32
font_array_height = output_rows * glyph_height
font_array = [[0] * font_array_width for i in range(font_array_height)]
for charIndex in range(len(chars)):
char = chars[charIndex]
base_x = (charIndex % output_cols) * glyph_width
base_y = (charIndex / output_cols) * glyph_height
# Render the character.
face.load_char(char)
bitmap = face.glyph.bitmap
left = face.glyph.bitmap_left
top = face.glyph.bitmap_top
width = bitmap.width
rows = bitmap.rows
pitch = bitmap.pitch
offset_x = left
offset_y = glyph_height - (top - glyph_descender)
# '#' in the smallest font generates a larger glyph than the "fixed" font width.
if offset_x + width > glyph_width:
offset_x = glyph_width - width
if offset_x < 0:
width += offset_x
offset_x = 0
base_x += offset_x
base_y += offset_y
assert (offset_x + width <= glyph_width)
assert (offset_y + rows <= glyph_height)
# Write the character bitmap in the font image.
for y in range(rows):
for x in range(width):
pixel_value = bitmap.buffer[y * pitch + x]
output_bit = 1 if pixel_value >= 122 else 0
font_array_row = base_y + y
font_array_col = (base_x + x) / 32
font_array_bit = (base_x + x) % 32
font_array[font_array_row][font_array_col] |= output_bit << font_array_bit
# Output the image to a C array.
data = 'constexpr uint32_t ' + font_array_name + '[' + font_height + '][' + font_width + '/32] = {\n'
for y in range(font_array_height):
data += '{'
for x in range(font_array_width):
data += '0x{:08X}, '.format(font_array[y][x])
data += '},\n'
data += '};\n'
font_glyph_widths.append(glyph_width)
font_glyph_heights.append(glyph_height)
font_layers.append('constexpr int ' + font_layer_symbol + ' = ' + font_layer + ';')
font_data.append(data)
get_font_layer_pixel.append(
template_get_font_layer_pixel.format(
layer=font_layer_symbol, font_image=font_array_name))
current_font_layer += 1
with open(out_file_h, 'w') as outfile:
outfile.write(
template_out_file_h.format(
script_name=__file__,
font_file=font_file,
copyright_year=date.today().year,
out_file_name=out_file_h,
font_count=len(font_data),
font_glyph_widths=','.join(map(str, font_glyph_widths)),
font_glyph_heights=','.join(map(str, font_glyph_heights)),
max_font_width=max(font_glyph_widths),
max_font_height=max(font_glyph_heights),
font_layers='\n'.join(font_layers)))
outfile.close()
font_layer_widths = [
'kFontGlyphWidths[' + str(layer) + '] * kFontCharactersPerRow'
for layer in range(len(font_data))
]
font_layer_heights = [
'kFontGlyphHeights[' + str(layer) + '] * kFontCharactersPerCol'
for layer in range(len(font_data))
]
with open(out_file_cpp, 'w') as outfile:
outfile.write(
template_out_file_cpp.format(
script_name=__file__,
font_file=font_file,
copyright_year=date.today().year,
out_file_name=out_file_cpp,
font_layer_widths=','.join(font_layer_widths),
font_layer_heights=','.join(font_layer_heights),
font_data='\n'.join(font_data),
get_font_layer_pixel=''.join(get_font_layer_pixel)))
outfile.close()
if __name__ == '__main__':
sys.exit(main())