balatro-gba/scripts/generate_font.py
Rickey 628c0c992d
Introduce decimal point font (#314)
* Introduce decimal point font

* Add png of font

* Add getting a decimal point str from int

* Move font out of utils

* Clang format

* set Readme.md as main page in docs

* Add font generator

* kind of fix font

* Fix image oddities

* Added pip install pillow to build_ci_workflow

* Added ensurepip

* Update Docker/CI for font generation

* Fix CI

* Fix CI forreal

* Another CI fix

* Fix directory name for rom

* Adjust directory

* Dummy commit for test

* Revert "Dummy commit for test"

This reverts commit b607085c13.

* dos2unix and update .gitignore

* Delete the generated font file

* Delete the generated font file

* remove dot from font

* Update include/font.h

Co-authored-by: MeirGavish <meir.gavish@gmail.com>

---------

Co-authored-by: MeirGavish <meir.gavish@gmail.com>
2025-12-18 18:19:01 -08:00

117 lines
2.8 KiB
Python

#!/usr/bin/env python3
from PIL import Image, ImageOps
import argparse
CHAR_WIDTH = 8
CHAR_HEIGHT = 8
NUM_VERT_CHARS = 6
NUM_HORZ_CHARS = 16
WORD_SIZE = 32
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input", required=True, help="input file")
parser.add_argument("-o", "--output", required=True, help="output file")
args = parser.parse_args()
in_path = args.input
out_path = args.output
# The font is stored in a 4-bit colormap png and is made of a grid of
# 16x6 characters:
# |-------------16---------------|
# | [][][][][][][][][][][][][][][][]
# | [][][][][][][][][][][][][][][][]
# 6 [][][][][][][][][][][][][][][][]
# | [][][][][][][][][][][][][][][][]
# | [][][][][][][][][][][][][][][][]
# | [][][][][][][][][][][][][][][][]
#
# Each character is a bitmap of 8x8 pixels.
#
# For example, the ! :
#
# ___00___
# ___00___
# ___00___
# ___00___
# ___00___
# ___00___
# ________
# ___00___
#
# The font file is organized to go character-by-character and left-to-right
img = Image.open(in_path)
img = img.convert("P")
img = img.convert('1')
img = ImageOps.invert(img)
glyphs = []
for char_y in range(NUM_VERT_CHARS):
for char_x in range(NUM_HORZ_CHARS):
# Get the 8x8 crop area at our current character in the image
pix_x = char_x * CHAR_WIDTH
pix_y = char_y * CHAR_HEIGHT
crop_area = (pix_x, pix_y, pix_x + CHAR_WIDTH, pix_y + CHAR_HEIGHT)
pixel_block_img = img.crop(crop_area)
pixels = list(pixel_block_img.getdata())
word0 = 0
word1 = 0
for i, pixel in enumerate(pixels):
bit = 1 if pixel > 0 else 0
if i < WORD_SIZE:
word0 = word0 | (bit << i)
else:
word1 = word1 | (bit << (i - WORD_SIZE))
glyphs.append((word0, word1))
NUM_WORDS_IN_ROW = 8
first = True
with open(out_path, "w") as out:
out.write("""
@{{BLOCK(gbalatro_sys8)
.section .rodata
.align 2
.global gbalatro_sys8Font
gbalatro_sys8Font:
.word gbalatro_sys8Glyphs, 0, 0
.hword 32, 96
.byte 8, 8
.byte 8, 8
.hword 8
.byte 1, 0
.section .rodata
.align 2
.global gbalatro_sys8Glyphs @ 768 bytes (192 unsigned ints)
gbalatro_sys8Glyphs:
""")
for i, glyph in enumerate(glyphs):
if first:
out.write(" .word ")
first = False
out.write(f"0x{glyph[0]:08X},0x{glyph[1]:08X}")
# This checks to see if we have reached NUM_WORDS_IN_ROW words, (divided by
# 2 because that's the number of entries in each char[])
if (((i + 1) % (NUM_WORDS_IN_ROW // 2)) == 0):
out.write("\n")
if i != (len(glyphs) - 1):
out.write(" .word ")
else:
out.write(",")
out.write("\n")
out.write("\n")
out.write('@}}BLOCK(gbalatro_sys8)\n')