Files
TeslaRel410/emulator/render_vdb_palettes.py
T
CydandClaude Opus 4.8 981d98d784 VDB: dump captured palettes (VDB_PALDUMP) + swatch renderer
VDB_PALDUMP=<prefix> writes each completed 768-byte palette load to
<prefix>N.rgb (256 RGB entries per VDB display group). render_vdb_palettes.py
renders each as a 16x16 swatch grid + linear ramp.

First capture: pal1 (aux1) is a structured red/green/olive/black color map
(2-bit R x 2-bit G) -- likely the color display's status coloring; pal0
(secondary, dynamic ~29 reloads) and pal2 (aux2) are grayscale, sampled black
mid-animation. Palettes are the per-display color maps the VDB applies when
splitting the framebuffer to the six monitors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:27:10 -05:00

68 lines
2.1 KiB
Python

#!/usr/bin/env python3
"""Render captured VDB palettes (VDB_PALDUMP <prefix>N.rgb) as swatch images.
Each .rgb is 256 RGB triplets (768 bytes) -- one of the VDB's three display
palette groups (secondary / aux1 / aux2). For each, emit:
<prefix>N.png -- a 16x16 grid of the 256 colors + a 256-wide linear ramp.
Usage: render_vdb_palettes.py <prefix> (e.g. .../scratchpad/vdbpal)
"""
import sys
from PIL import Image, ImageDraw, ImageFont
NAMES = {0: "secondary (dynamic)", 1: "aux 1", 2: "aux 2"}
def render_one(path, out, title):
data = open(path, "rb").read()
if len(data) < 768:
data = data + b"\x00" * (768 - len(data))
cols = [(data[i * 3], data[i * 3 + 1], data[i * 3 + 2]) for i in range(256)]
cell, grid = 28, 16
gw = cell * grid
ramp_h = 40
pad, top = 12, 34
W = gw + pad * 2
H = top + gw + 10 + ramp_h + pad
img = Image.new("RGB", (W, H), (24, 24, 28))
d = ImageDraw.Draw(img)
try:
font = ImageFont.truetype("consola.ttf", 16)
except Exception:
font = ImageFont.load_default()
d.text((pad, 8), title, fill=(230, 230, 235), font=font)
# 16x16 swatch grid (index 0 top-left, row-major)
for i, c in enumerate(cols):
x = pad + (i % grid) * cell
y = top + (i // grid) * cell
d.rectangle([x, y, x + cell - 1, y + cell - 1], fill=c)
# linear ramp strip below
ry = top + gw + 10
for i, c in enumerate(cols):
x0 = pad + i * (gw / 256.0)
x1 = pad + (i + 1) * (gw / 256.0)
d.rectangle([x0, ry, x1, ry + ramp_h], fill=c)
d.rectangle([pad, ry, pad + gw, ry + ramp_h], outline=(80, 80, 88))
img.save(out)
# quick stats
grays = sum(1 for r, g, b in cols if abs(r - g) < 6 and abs(g - b) < 6)
print(f"{out}: {grays}/256 grayscale-ish entries")
def main():
prefix = sys.argv[1]
for g in (0, 1, 2):
p = f"{prefix}{g}.rgb"
try:
render_one(p, f"{prefix}{g}.png",
f"VDB palette {g} - {NAMES.get(g, '')}")
except FileNotFoundError:
print(f"(no {p})")
if __name__ == "__main__":
main()