8bitlenser/lenser/c16/palette.py
2026-07-03 19:35:35 -07:00

62 lines
3.6 KiB
Python

"""Commodore 16 / Plus4 TED (7360/8360) colour palette.
The TED produces 128 colours arranged as 8 luminance levels x 16 hues. A colour
value is 7-bit: bits 0-3 = hue (0-15), bits 4-6 = luminance (0-7), so the palette
index is ``(luminance << 4) | hue``. Hue 0 is (near) black at every luminance and
hue 1 is the neutral grey ramp, so true greys are available too.
RGB values are taken verbatim from MAME's ``mos7360`` PALETTE_MOS table so the
encoder matches what the emulator renders.
"""
from __future__ import annotations
import numpy as np
from ..palette import srgb_to_lab
# 128 entries in (luminance<<4)|hue order, copied from MAME's mos7360.cpp.
TED = np.array([
(0x06, 0x01, 0x03), (0x2b, 0x2b, 0x2b), (0x67, 0x0e, 0x0f), (0x00, 0x3f, 0x42),
(0x57, 0x00, 0x6d), (0x00, 0x4e, 0x00), (0x19, 0x1c, 0x94), (0x38, 0x38, 0x00),
(0x56, 0x20, 0x00), (0x4b, 0x28, 0x00), (0x16, 0x48, 0x00), (0x69, 0x07, 0x2f),
(0x00, 0x46, 0x26), (0x06, 0x2a, 0x80), (0x2a, 0x14, 0x9b), (0x0b, 0x49, 0x00),
(0x00, 0x03, 0x02), (0x3d, 0x3d, 0x3d), (0x75, 0x1e, 0x20), (0x00, 0x50, 0x4f),
(0x6a, 0x10, 0x78), (0x04, 0x5c, 0x00), (0x2a, 0x2a, 0xa3), (0x4c, 0x47, 0x00),
(0x69, 0x2f, 0x00), (0x59, 0x38, 0x00), (0x26, 0x56, 0x00), (0x75, 0x15, 0x41),
(0x00, 0x58, 0x3d), (0x15, 0x3d, 0x8f), (0x39, 0x22, 0xae), (0x19, 0x59, 0x00),
(0x00, 0x03, 0x04), (0x42, 0x42, 0x42), (0x7b, 0x28, 0x20), (0x02, 0x56, 0x59),
(0x6f, 0x1a, 0x82), (0x0a, 0x65, 0x09), (0x30, 0x34, 0xa7), (0x50, 0x51, 0x00),
(0x6e, 0x36, 0x00), (0x65, 0x40, 0x00), (0x2c, 0x5c, 0x00), (0x7d, 0x1e, 0x45),
(0x01, 0x61, 0x45), (0x1c, 0x45, 0x99), (0x42, 0x2d, 0xad), (0x1d, 0x62, 0x00),
(0x05, 0x00, 0x02), (0x56, 0x55, 0x5a), (0x90, 0x3c, 0x3b), (0x17, 0x6d, 0x72),
(0x87, 0x2d, 0x99), (0x1f, 0x7b, 0x15), (0x46, 0x49, 0xc1), (0x66, 0x63, 0x00),
(0x84, 0x4c, 0x0d), (0x73, 0x55, 0x00), (0x40, 0x72, 0x00), (0x91, 0x33, 0x5e),
(0x19, 0x74, 0x5c), (0x32, 0x59, 0xae), (0x59, 0x3f, 0xc3), (0x32, 0x76, 0x00),
(0x02, 0x01, 0x06), (0x84, 0x7e, 0x85), (0xbb, 0x67, 0x68), (0x45, 0x96, 0x96),
(0xaf, 0x58, 0xc3), (0x4a, 0xa7, 0x3e), (0x73, 0x73, 0xec), (0x92, 0x8d, 0x11),
(0xaf, 0x78, 0x32), (0xa1, 0x80, 0x20), (0x6c, 0x9e, 0x12), (0xba, 0x5f, 0x89),
(0x46, 0x9f, 0x83), (0x61, 0x85, 0xdd), (0x84, 0x6c, 0xef), (0x5d, 0xa3, 0x29),
(0x02, 0x00, 0x0a), (0xb2, 0xac, 0xb3), (0xe9, 0x92, 0x92), (0x6c, 0xc3, 0xc1),
(0xd9, 0x86, 0xf0), (0x79, 0xd1, 0x76), (0x9d, 0xa1, 0xff), (0xbd, 0xbe, 0x40),
(0xdc, 0xa2, 0x61), (0xd1, 0xa9, 0x4c), (0x93, 0xc8, 0x3d), (0xe9, 0x8a, 0xb1),
(0x6f, 0xcd, 0xab), (0x8a, 0xb4, 0xff), (0xb2, 0x9a, 0xff), (0x88, 0xcb, 0x59),
(0x02, 0x00, 0x0a), (0xc7, 0xca, 0xc9), (0xff, 0xac, 0xac), (0x85, 0xd8, 0xe0),
(0xf3, 0x9c, 0xff), (0x92, 0xea, 0x8a), (0xb7, 0xba, 0xff), (0xd6, 0xd3, 0x5b),
(0xf3, 0xbe, 0x79), (0xe6, 0xc5, 0x65), (0xb0, 0xe0, 0x57), (0xff, 0xa4, 0xcf),
(0x89, 0xe5, 0xc8), (0xa4, 0xca, 0xff), (0xca, 0xb3, 0xff), (0xa2, 0xe5, 0x7a),
(0x01, 0x01, 0x01), (0xff, 0xff, 0xff), (0xff, 0xf6, 0xf2), (0xd1, 0xff, 0xff),
(0xff, 0xe9, 0xff), (0xdb, 0xff, 0xd3), (0xfd, 0xff, 0xff), (0xff, 0xff, 0xa3),
(0xff, 0xff, 0xc1), (0xff, 0xff, 0xb2), (0xfc, 0xff, 0xa2), (0xff, 0xee, 0xff),
(0xd1, 0xff, 0xff), (0xeb, 0xff, 0xff), (0xff, 0xf8, 0xff), (0xed, 0xff, 0xbc),
], dtype=np.float64)
# Neutral grey ramp (hue 1) plus black -- used by the monochrome mode.
GREYS = [0, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71] # (lum<<4)|1, lum 0..7
def get_palette() -> np.ndarray:
return TED
def palette_lab() -> np.ndarray:
return srgb_to_lab(TED)