First public commit.
This commit is contained in:
parent
2a48f52979
commit
4bac9d83ed
288 changed files with 18417 additions and 1076 deletions
58
lenser/nes/palette.py
Normal file
58
lenser/nes/palette.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
"""Nintendo Entertainment System (2C02 PPU) master palette.
|
||||
|
||||
The NES has no fixed RGB palette -- the PPU generates an NTSC signal. We
|
||||
reproduce MAME's exact ``nespal_to_RGB`` (YUV->RGB) formula so the encoder
|
||||
matches what the emulator renders. A palette value is a 6-bit index 0-63:
|
||||
high nibble = luminance (0-3), low nibble = hue (0-15, with 0/13/14/15 greyscale).
|
||||
The byte written to PPU palette RAM IS this index, so ``PALETTE``/``GREYS`` are
|
||||
indexed by the hardware value.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ..palette import srgb_to_lab
|
||||
|
||||
_TINT, _HUE = 0.22, 287.0
|
||||
_Kr, _Kb, _Ku, _Kv = 0.2989, 0.1145, 2.029, 1.140
|
||||
_BRIGHT = [[0.50, 0.75, 1.0, 1.0],
|
||||
[0.29, 0.45, 0.73, 0.9],
|
||||
[0.0, 0.24, 0.47, 0.77]]
|
||||
|
||||
|
||||
def _rgb(intensity: int, num: int):
|
||||
if num == 0:
|
||||
sat = rad = 0.0; y = _BRIGHT[0][intensity]
|
||||
elif num == 13:
|
||||
sat = rad = 0.0; y = _BRIGHT[2][intensity]
|
||||
elif num in (14, 15):
|
||||
sat = rad = y = 0.0
|
||||
else:
|
||||
sat = _TINT; rad = math.radians(num * 30 + _HUE); y = _BRIGHT[1][intensity]
|
||||
u, v = sat * math.cos(rad), sat * math.sin(rad)
|
||||
R = (y + _Kv * v) * 255.0
|
||||
G = (y - (_Kb * _Ku * u + _Kr * _Kv * v) / (1 - _Kb - _Kr)) * 255.0
|
||||
B = (y + _Ku * u) * 255.0
|
||||
cl = lambda x: max(0, min(255, int(math.floor(x + 0.5))))
|
||||
return (cl(R), cl(G), cl(B))
|
||||
|
||||
|
||||
PALETTE = np.array([_rgb(i >> 4, i & 0x0F) for i in range(64)], dtype=np.float64)
|
||||
|
||||
# Distinct grey ramp (R==G==B), sorted dark->light, deduped by luminance.
|
||||
_grey = {}
|
||||
for _i in range(64):
|
||||
r, g, b = PALETTE[_i]
|
||||
if r == g == b:
|
||||
_grey.setdefault(int(r), _i)
|
||||
GREYS = [_grey[k] for k in sorted(_grey)] # e.g. $0F,$1D,$2D,$10,$20
|
||||
|
||||
|
||||
def get_palette() -> np.ndarray:
|
||||
return PALETTE
|
||||
|
||||
|
||||
def palette_lab() -> np.ndarray:
|
||||
return srgb_to_lab(PALETTE)
|
||||
Loading…
Add table
Add a link
Reference in a new issue