4a6bdb6fe4
This fixes the bug that bitmap changes do not cause screen updates and optimizes the refresh when the bitmap is simply shown on the screen. If the bitmap is used in tiles, then changing it will cause all TileGrids using it to do a full refresh. Fixes #1981
189 lines
5.3 KiB
Python
189 lines
5.3 KiB
Python
import argparse
|
|
|
|
import os
|
|
import struct
|
|
import sys
|
|
|
|
sys.path.append("bitmap_font")
|
|
sys.path.append("../../tools/bitmap_font")
|
|
|
|
from adafruit_bitmap_font import bitmap_font
|
|
|
|
parser = argparse.ArgumentParser(description='Generate USB descriptors.')
|
|
parser.add_argument('--font', type=str,
|
|
help='Font path', required=True)
|
|
parser.add_argument('--extra_characters', type=str,
|
|
help='Unicode string of extra characters')
|
|
parser.add_argument('--sample_file', type=argparse.FileType('r'),
|
|
help='Text file that includes strings to support.')
|
|
parser.add_argument('--output_c_file', type=argparse.FileType('w'), required=True)
|
|
|
|
args = parser.parse_args()
|
|
|
|
class BitmapStub:
|
|
def __init__(self, width, height, color_depth):
|
|
self.width = width
|
|
self.rows = [b''] * height
|
|
|
|
def _load_row(self, y, row):
|
|
self.rows[y] = bytes(row)
|
|
|
|
f = bitmap_font.load_font(args.font, BitmapStub)
|
|
|
|
# Load extra characters from the sample file.
|
|
sample_characters = set()
|
|
if args.sample_file:
|
|
for line in args.sample_file:
|
|
# Skip comments because we add additional characters in our huffman comments.
|
|
if line.startswith("//"):
|
|
continue
|
|
for c in line.strip():
|
|
sample_characters.add(c)
|
|
|
|
# Merge visible ascii, sample characters and extra characters.
|
|
visible_ascii = bytes(range(0x20, 0x7f)).decode("utf-8")
|
|
all_characters = visible_ascii
|
|
for c in sample_characters:
|
|
if c not in all_characters:
|
|
all_characters += c
|
|
if args.extra_characters:
|
|
all_characters.extend(args.extra_characters)
|
|
filtered_characters = all_characters
|
|
|
|
# Try to pre-load all of the glyphs. Misses will still be slow later.
|
|
f.load_glyphs(set(all_characters))
|
|
|
|
# Get each glyph.
|
|
for c in all_characters:
|
|
g = f.get_glyph(ord(c))
|
|
if not g:
|
|
print("Font missing character:", c, ord(c))
|
|
filtered_characters = filtered_characters.replace(c, "")
|
|
continue
|
|
if g["shift"][1] != 0:
|
|
raise RuntimeError("y shift")
|
|
|
|
x, y, dx, dy = f.get_bounding_box()
|
|
tile_x, tile_y = x - dx, y - dy
|
|
total_bits = tile_x * len(all_characters)
|
|
total_bits += 32 - total_bits % 32
|
|
bytes_per_row = total_bits // 8
|
|
b = bytearray(bytes_per_row * tile_y)
|
|
|
|
for x, c in enumerate(filtered_characters):
|
|
g = f.get_glyph(ord(c))
|
|
start_bit = x * tile_x + g["bounds"][2]
|
|
start_y = (tile_y - 2) - (g["bounds"][1] + g["bounds"][3])
|
|
for y, row in enumerate(g["bitmap"].rows):
|
|
for i in range(g["bounds"][0]):
|
|
byte = i // 8
|
|
bit = i % 8
|
|
if row[byte] & (1 << (7-bit)) != 0:
|
|
overall_bit = start_bit + (start_y + y) * bytes_per_row * 8 + i
|
|
b[overall_bit // 8] |= 1 << (7 - (overall_bit % 8))
|
|
|
|
|
|
extra_characters = ""
|
|
for c in filtered_characters:
|
|
if c not in visible_ascii:
|
|
extra_characters += c
|
|
|
|
c_file = args.output_c_file
|
|
|
|
c_file.write("""\
|
|
|
|
#include "shared-bindings/displayio/Palette.h"
|
|
#include "supervisor/shared/display.h"
|
|
|
|
""")
|
|
|
|
c_file.write("""\
|
|
uint32_t terminal_transparency[1] = {0x00000000};
|
|
|
|
// These colors are RGB 565 with the bytes swapped.
|
|
uint32_t terminal_colors[1] = {0xffff0000};
|
|
|
|
displayio_palette_t supervisor_terminal_color = {
|
|
.base = {.type = &displayio_palette_type },
|
|
.opaque = terminal_transparency,
|
|
.colors = terminal_colors,
|
|
.color_count = 2,
|
|
.needs_refresh = false
|
|
};
|
|
""")
|
|
|
|
c_file.write("""\
|
|
displayio_tilegrid_t supervisor_terminal_text_grid = {{
|
|
.base = {{ .type = &displayio_tilegrid_type }},
|
|
.bitmap = (displayio_bitmap_t*) &supervisor_terminal_font_bitmap,
|
|
.pixel_shader = &supervisor_terminal_color,
|
|
.x = 16,
|
|
.y = 0,
|
|
.pixel_width = {1},
|
|
.pixel_height = {2},
|
|
.bitmap_width_in_tiles = {0},
|
|
.tiles_in_bitmap = {0},
|
|
.width_in_tiles = 1,
|
|
.height_in_tiles = 1,
|
|
.tile_width = {1},
|
|
.tile_height = {2},
|
|
.tiles = NULL,
|
|
.partial_change = false,
|
|
.full_change = false,
|
|
.first_draw = true,
|
|
.moved = false,
|
|
.inline_tiles = false,
|
|
.in_group = true
|
|
}};
|
|
""".format(len(all_characters), tile_x, tile_y))
|
|
|
|
c_file.write("""\
|
|
const uint32_t font_bitmap_data[{}] = {{
|
|
""".format(bytes_per_row * tile_y // 4))
|
|
|
|
for i, word in enumerate(struct.iter_unpack(">I", b)):
|
|
c_file.write("0x{:08x}, ".format(word[0]))
|
|
if (i + 1) % (bytes_per_row // 4) == 0:
|
|
c_file.write("\n")
|
|
|
|
c_file.write("""\
|
|
};
|
|
""")
|
|
|
|
c_file.write("""\
|
|
displayio_bitmap_t supervisor_terminal_font_bitmap = {{
|
|
.base = {{.type = &displayio_bitmap_type }},
|
|
.width = {},
|
|
.height = {},
|
|
.data = (size_t*) font_bitmap_data,
|
|
.stride = {},
|
|
.bits_per_value = 1,
|
|
.x_shift = 5,
|
|
.x_mask = 0x1f,
|
|
.bitmask = 0x1,
|
|
.read_only = true
|
|
}};
|
|
""".format(len(all_characters) * tile_x, tile_y, bytes_per_row / 4))
|
|
|
|
|
|
c_file.write("""\
|
|
const fontio_builtinfont_t supervisor_terminal_font = {{
|
|
.base = {{.type = &fontio_builtinfont_type }},
|
|
.bitmap = &supervisor_terminal_font_bitmap,
|
|
.width = {},
|
|
.height = {},
|
|
.unicode_characters = (const uint8_t*) "{}",
|
|
.unicode_characters_len = {}
|
|
}};
|
|
""".format(tile_x, tile_y, extra_characters, len(extra_characters.encode("utf-8"))))
|
|
|
|
c_file.write("""\
|
|
terminalio_terminal_obj_t supervisor_terminal = {
|
|
.base = { .type = &terminalio_terminal_type },
|
|
.font = &supervisor_terminal_font,
|
|
.cursor_x = 0,
|
|
.cursor_y = 0,
|
|
.tilegrid = &supervisor_terminal_text_grid
|
|
};
|
|
""")
|