Override blend mode, FPS sparkline, fix api_input persistence
New features: - Override composite blend mode: per-pixel alpha from brightness (black=transparent, bright=opaque). Ideal for API input over effects. - API input test preview FPS chart uses shared createFpsSparkline (same look as target card charts) Fixes: - Fix api_input source not surviving server restart: from_dict was still passing removed led_count field to constructor - Fix composite layer brightness/processing selectors not aligned: labels get fixed width, selects fill remaining space - Fix CSPT input selector showing in non-CSPT CSS test mode - Fix test modal LED/FPS controls showing for api_input sources - Server only sends test WS frames when api_input push_generation changes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ _BLEND_NORMAL = "normal"
|
||||
_BLEND_ADD = "add"
|
||||
_BLEND_MULTIPLY = "multiply"
|
||||
_BLEND_SCREEN = "screen"
|
||||
_BLEND_OVERRIDE = "override"
|
||||
|
||||
|
||||
class CompositeColorStripStream(ColorStripStream):
|
||||
@@ -300,11 +301,34 @@ class CompositeColorStripStream(ColorStripStream):
|
||||
u16a >>= 8
|
||||
np.copyto(out, u16a, casting="unsafe")
|
||||
|
||||
def _blend_override(self, bottom: np.ndarray, top: np.ndarray, alpha: int,
|
||||
out: np.ndarray) -> None:
|
||||
"""Override blend: per-pixel alpha derived from top brightness.
|
||||
|
||||
Black pixels are fully transparent (bottom shows through),
|
||||
bright pixels fully opaque (top replaces bottom). Layer opacity
|
||||
scales the per-pixel alpha.
|
||||
"""
|
||||
u16a, u16b = self._u16_a, self._u16_b
|
||||
# Per-pixel brightness = max(R, G, B) for each LED
|
||||
per_px_alpha = np.max(top, axis=1, keepdims=True).astype(np.uint16)
|
||||
# Scale by layer opacity
|
||||
per_px_alpha = (per_px_alpha * alpha) >> 8
|
||||
# Lerp: out = (bottom * (256 - per_px_alpha) + top * per_px_alpha) >> 8
|
||||
np.copyto(u16a, bottom, casting="unsafe")
|
||||
np.copyto(u16b, top, casting="unsafe")
|
||||
u16a *= (256 - per_px_alpha)
|
||||
u16b *= per_px_alpha
|
||||
u16a += u16b
|
||||
u16a >>= 8
|
||||
np.copyto(out, u16a, casting="unsafe")
|
||||
|
||||
_BLEND_DISPATCH = {
|
||||
_BLEND_NORMAL: "_blend_normal",
|
||||
_BLEND_ADD: "_blend_add",
|
||||
_BLEND_MULTIPLY: "_blend_multiply",
|
||||
_BLEND_SCREEN: "_blend_screen",
|
||||
_BLEND_OVERRIDE: "_blend_override",
|
||||
}
|
||||
|
||||
# ── Processing loop ─────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user