First public commit.
This commit is contained in:
parent
2a48f52979
commit
4bac9d83ed
288 changed files with 18417 additions and 1076 deletions
107
lenser/apple/palette.py
Normal file
107
lenser/apple/palette.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
"""Apple II colour palettes and the HGR memory-layout helper.
|
||||
|
||||
- HGR mono: black/white (the 280x192 1-bit bitmap displayed as monochrome).
|
||||
- HGR colour: 6 NTSC "artifact" colours (added later).
|
||||
- DHGR: 16 colours (added later).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ..palette import srgb_to_lab
|
||||
|
||||
# Monochrome (white phosphor) pair.
|
||||
MONO = np.array([(0, 0, 0), (255, 255, 255)], dtype=np.float64)
|
||||
|
||||
# Double-Hi-Res 16-colour palette, indexed by the 4-bit value -- measured from
|
||||
# MAME's apple2ee DHGR output so the encoder's nibble values map to exactly what
|
||||
# the //e displays.
|
||||
DHGR16 = np.array([
|
||||
(0x00, 0x00, 0x00), # 0 black
|
||||
(0x40, 0x1c, 0xf7), # 1 blue
|
||||
(0x00, 0x74, 0x40), # 2 dark green
|
||||
(0x19, 0x90, 0xff), # 3 medium blue
|
||||
(0x40, 0x63, 0x00), # 4 olive / dark green
|
||||
(0x80, 0x80, 0x80), # 5 grey
|
||||
(0x19, 0xd7, 0x00), # 6 green
|
||||
(0x58, 0xf4, 0xbf), # 7 aqua
|
||||
(0xa7, 0x0b, 0x40), # 8 dark red / magenta
|
||||
(0xe6, 0x28, 0xff), # 9 magenta / violet
|
||||
(0x80, 0x80, 0x80), # 10 grey
|
||||
(0xbf, 0x9c, 0xff), # 11 lavender
|
||||
(0xe6, 0x6f, 0x00), # 12 orange
|
||||
(0xff, 0x8b, 0xbf), # 13 pink
|
||||
(0xbf, 0xe3, 0x08), # 14 yellow-green
|
||||
(0xff, 0xff, 0xff), # 15 white
|
||||
], dtype=np.float64)
|
||||
|
||||
|
||||
# HGR NTSC "artifact" colours. Per 7-pixel byte a palette bit selects one of two
|
||||
# colour pairs; the displayed colour of an "on" pixel also depends on its column
|
||||
# parity (and two adjacent on-pixels read as white).
|
||||
# palette 0: even column -> violet, odd column -> green
|
||||
# palette 1: even column -> blue, odd column -> orange
|
||||
HGR_BLACK, HGR_VIOLET, HGR_GREEN, HGR_WHITE, HGR_BLUE, HGR_ORANGE = 0, 1, 2, 3, 4, 5
|
||||
HGR6 = np.array([
|
||||
(0x00, 0x00, 0x00), # black
|
||||
(0xd0, 0x3a, 0xff), # violet
|
||||
(0x20, 0xc8, 0x00), # green
|
||||
(0xff, 0xff, 0xff), # white
|
||||
(0x20, 0x9a, 0xff), # blue
|
||||
(0xff, 0x6a, 0x20), # orange
|
||||
], dtype=np.float64)
|
||||
|
||||
|
||||
def mono_lab() -> np.ndarray:
|
||||
return srgb_to_lab(MONO)
|
||||
|
||||
|
||||
def hgr6_lab() -> np.ndarray:
|
||||
return srgb_to_lab(HGR6)
|
||||
|
||||
|
||||
def pack_hgr_color(bits280: np.ndarray, pal_byte: np.ndarray) -> bytes:
|
||||
"""280x192 mono bits + (192x40) per-byte palette bit -> 8192 HGR buffer."""
|
||||
buf = bytearray(0x2000)
|
||||
H = bits280.shape[0]
|
||||
for y in range(H):
|
||||
base = hgr_row_addr(y)
|
||||
row = bits280[y]
|
||||
for bx in range(40):
|
||||
b = 0
|
||||
for i in range(7):
|
||||
if row[bx * 7 + i]:
|
||||
b |= (1 << i)
|
||||
if pal_byte[y, bx]:
|
||||
b |= 0x80
|
||||
buf[base + bx] = b
|
||||
return bytes(buf)
|
||||
|
||||
|
||||
def dhgr_lab() -> np.ndarray:
|
||||
return srgb_to_lab(DHGR16)
|
||||
|
||||
|
||||
def hgr_row_addr(y: int) -> int:
|
||||
"""Offset (from $2000) of HGR row ``y`` (0..191) in the interleaved layout."""
|
||||
return (y & 7) * 0x400 + ((y >> 3) & 7) * 0x80 + (y >> 6) * 0x28
|
||||
|
||||
|
||||
def pack_hgr_mono(val_image: np.ndarray) -> bytes:
|
||||
"""280x192 1-bit image -> 8192-byte HGR page 1 buffer.
|
||||
|
||||
7 pixels per byte, bit 0 = leftmost, bit 7 (palette bit) = 0 for mono.
|
||||
"""
|
||||
buf = bytearray(0x2000)
|
||||
H, W = val_image.shape
|
||||
for y in range(H):
|
||||
base = hgr_row_addr(y)
|
||||
row = val_image[y]
|
||||
for bx in range(40):
|
||||
b = 0
|
||||
for i in range(7):
|
||||
if row[bx * 7 + i]:
|
||||
b |= (1 << i)
|
||||
buf[base + bx] = b
|
||||
return bytes(buf)
|
||||
Loading…
Add table
Add a link
Reference in a new issue