Files
bigmak94andClaude Opus 5.5 bd9bded792 GalaxyQuest: Super Mario Galaxy in VR on Meta Quest 3
A native port built on the Petari decompilation (previous commit): an
HLE platform layer (OS, DVD, GX, audio, input, NAND) under the game's
own code, an OpenXR presentation (a diorama around the player, a giant
screen, the HUD and settings as compositor layers, SpaceWarp, dynamic
resolution), Touch Plus controls, the tools that convert your own game
files (tools/cook, which also takes the few pieces of data the game's
executable holds from your sys/main.dol), and the port's changes to the
decompilation (`git diff petari-base -- decomp`).  README.md explains
installing and building, docs/TECHNICAL.md how it works.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:59:38 +02:00

112 lines
4.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Bakes the glyph atlas the VR layer's own panels draw text with
(platform/src/xr/ui_font.h).
make_ui_font.py <font.ttf> <output.h>
Needs Pillow. The port uses Inter Bold (SIL Open Font License 1.1), e.g.
from tools/ref/dusklight/res/Inter-Bold.ttf. Printable ASCII and a few
symbols are rendered at each size in SIZES as 4-bit coverage, packed into one
atlas per size and stored base64-encoded.
"""
import base64
import sys
from PIL import Image, ImageDraw, ImageFont
SIZES = (40, 28)
CHARS = [chr(c) for c in range(32, 127)] + ['−', '·'] # minus sign, middle dot
ATLAS_W = 512
def bake(path, size):
font = ImageFont.truetype(path, size)
ascent, descent = font.getmetrics()
glyphs = []
for ch in CHARS:
left, top, right, bottom = font.getbbox(ch, anchor='ls')
w, h = max(0, right - left), max(0, bottom - top)
img = Image.new('L', (max(w, 1), max(h, 1)), 0)
if w and h:
ImageDraw.Draw(img).text((-left, -top), ch, font=font, fill=255, anchor='ls')
advance = int(round(font.getlength(ch) * 4))
glyphs.append({'code': ord(ch), 'img': img, 'w': w, 'h': h, 'left': left, 'top': -top, 'advance': advance})
# Shelf packing, tallest first, a pixel of space around each glyph.
x = y = shelf = 1
for g in sorted(glyphs, key=lambda g: -g['h']):
if x + g['w'] + 1 > ATLAS_W:
x, y, shelf = 1, y + shelf + 1, 1
g['x'], g['y'] = x, y
x += g['w'] + 1
shelf = max(shelf, g['h'])
height = y + shelf + 1
atlas = Image.new('L', (ATLAS_W, height), 0)
for g in glyphs:
if g['w'] and g['h']:
atlas.paste(g['img'], (g['x'], g['y']))
px = atlas.tobytes()
packed = bytearray()
for i in range(0, len(px), 2):
hi = (px[i] * 15 + 127) // 255
lo = (px[i + 1] * 15 + 127) // 255 if i + 1 < len(px) else 0
packed.append(hi << 4 | lo)
return {'size': size, 'ascent': ascent, 'descent': descent, 'height': height, 'glyphs': glyphs, 'data': base64.b64encode(bytes(packed)).decode()}
def main():
if len(sys.argv) != 3:
sys.exit(__doc__)
faces = [bake(sys.argv[1], s) for s in SIZES]
out = []
out.append('// Generated by tools/make_ui_font.py from Inter Bold: do not edit.')
out.append('// Inter: Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter),')
out.append('// licensed under the SIL Open Font License, Version 1.1 (https://openfontlicense.org).')
out.append('#pragma once')
out.append('#include <stdint.h>')
out.append('')
out.append('namespace ui_font {')
out.append('')
out.append('// A glyph in its atlas; `left` and `top` place its box relative to the pen on')
out.append('// the baseline (top: pixels above it), advance is in quarter pixels.')
out.append('struct Glyph {')
out.append(' uint16_t code, x, y;')
out.append(' uint8_t w, h;')
out.append(' int8_t left, top;')
out.append(' uint16_t advance;')
out.append('};')
out.append('')
out.append('// Atlas: `width` x `height` 4-bit coverage values, two per byte (high')
out.append('// nibble first), base64-encoded.')
out.append('struct Face {')
out.append(' int size, ascent, descent, width, height;')
out.append(' const Glyph* glyphs;')
out.append(' int count;')
out.append(' const char* atlas;')
out.append('};')
for f in faces:
n = f['size']
out.append('')
out.append('static const Glyph kGlyphs%d[] = {' % n)
for g in f['glyphs']:
out.append(' {%d, %d, %d, %d, %d, %d, %d, %d},' % (g['code'], g['x'], g['y'], g['w'], g['h'], g['left'], g['top'], g['advance']))
out.append('};')
out.append('static const char kAtlas%d[] =' % n)
data = f['data']
for i in range(0, len(data), 120):
out.append(' "%s"' % data[i:i + 120])
out.append(' ;')
out.append('')
out.append('static const Face kFaces[] = {')
for f in faces:
n = f['size']
out.append(' {%d, %d, %d, %d, %d, kGlyphs%d, %d, kAtlas%d},' % (n, f['ascent'], f['descent'], ATLAS_W, f['height'], n, len(f['glyphs']), n))
out.append('};')
out.append('')
out.append('} // namespace ui_font')
with open(sys.argv[2], 'w', newline='\n') as fp:
fp.write('\n'.join(out) + '\n')
if __name__ == '__main__':
main()