forked from genewildish/Mainline
refactor(legacy): Delete scroll.py - fully deprecated rendering orchestrator (Phase 3.1)
- Delete engine/scroll.py (156 lines, deprecated rendering/orchestration) - No production code imports scroll.py - All functionality replaced by Stage-based pipeline architecture - Tests pass (521 passing, no change)
This commit is contained in:
156
engine/scroll.py
156
engine/scroll.py
@@ -1,156 +0,0 @@
|
|||||||
"""
|
|
||||||
Render engine — ticker content, scroll motion, message panel, and firehose overlay.
|
|
||||||
Orchestrates viewport, frame timing, and layers.
|
|
||||||
|
|
||||||
.. deprecated::
|
|
||||||
This module contains legacy rendering/orchestration code. New pipeline code should
|
|
||||||
use the Stage-based pipeline architecture instead. This module is
|
|
||||||
maintained for backwards compatibility with the demo mode.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import random
|
|
||||||
import time
|
|
||||||
|
|
||||||
from engine import config
|
|
||||||
from engine.camera import Camera
|
|
||||||
from engine.display import (
|
|
||||||
Display,
|
|
||||||
TerminalDisplay,
|
|
||||||
)
|
|
||||||
from engine.display import (
|
|
||||||
get_monitor as _get_display_monitor,
|
|
||||||
)
|
|
||||||
from engine.frame import calculate_scroll_step
|
|
||||||
from engine.layers import (
|
|
||||||
apply_glitch,
|
|
||||||
process_effects,
|
|
||||||
render_firehose,
|
|
||||||
render_message_overlay,
|
|
||||||
render_ticker_zone,
|
|
||||||
)
|
|
||||||
from engine.viewport import th, tw
|
|
||||||
|
|
||||||
USE_EFFECT_CHAIN = True
|
|
||||||
|
|
||||||
|
|
||||||
def stream(
|
|
||||||
items,
|
|
||||||
ntfy_poller,
|
|
||||||
mic_monitor,
|
|
||||||
display: Display | None = None,
|
|
||||||
camera: Camera | None = None,
|
|
||||||
):
|
|
||||||
"""Main render loop with four layers: message, ticker, scroll motion, firehose."""
|
|
||||||
if display is None:
|
|
||||||
display = TerminalDisplay()
|
|
||||||
if camera is None:
|
|
||||||
camera = Camera.vertical()
|
|
||||||
|
|
||||||
random.shuffle(items)
|
|
||||||
pool = list(items)
|
|
||||||
seen = set()
|
|
||||||
queued = 0
|
|
||||||
|
|
||||||
time.sleep(0.5)
|
|
||||||
w, h = tw(), th()
|
|
||||||
display.init(w, h)
|
|
||||||
display.clear()
|
|
||||||
fh = config.FIREHOSE_H if config.FIREHOSE else 0
|
|
||||||
ticker_view_h = h - fh
|
|
||||||
GAP = 3
|
|
||||||
scroll_step_interval = calculate_scroll_step(config.SCROLL_DUR, ticker_view_h)
|
|
||||||
|
|
||||||
active = []
|
|
||||||
ticker_next_y = ticker_view_h
|
|
||||||
noise_cache = {}
|
|
||||||
scroll_motion_accum = 0.0
|
|
||||||
msg_cache = (None, None)
|
|
||||||
frame_number = 0
|
|
||||||
|
|
||||||
while True:
|
|
||||||
if queued >= config.HEADLINE_LIMIT and not active:
|
|
||||||
break
|
|
||||||
|
|
||||||
t0 = time.monotonic()
|
|
||||||
w, h = tw(), th()
|
|
||||||
fh = config.FIREHOSE_H if config.FIREHOSE else 0
|
|
||||||
ticker_view_h = h - fh
|
|
||||||
scroll_step_interval = calculate_scroll_step(config.SCROLL_DUR, ticker_view_h)
|
|
||||||
|
|
||||||
msg = ntfy_poller.get_active_message()
|
|
||||||
msg_overlay, msg_cache = render_message_overlay(msg, w, h, msg_cache)
|
|
||||||
|
|
||||||
buf = []
|
|
||||||
ticker_h = ticker_view_h
|
|
||||||
|
|
||||||
scroll_motion_accum += config.FRAME_DT
|
|
||||||
while scroll_motion_accum >= scroll_step_interval:
|
|
||||||
scroll_motion_accum -= scroll_step_interval
|
|
||||||
camera.update(config.FRAME_DT)
|
|
||||||
|
|
||||||
while (
|
|
||||||
ticker_next_y < camera.y + ticker_view_h + 10
|
|
||||||
and queued < config.HEADLINE_LIMIT
|
|
||||||
):
|
|
||||||
from engine.effects import next_headline
|
|
||||||
from engine.render import make_block
|
|
||||||
|
|
||||||
t, src, ts = next_headline(pool, items, seen)
|
|
||||||
ticker_content, hc, midx = make_block(t, src, ts, w)
|
|
||||||
active.append((ticker_content, hc, ticker_next_y, midx))
|
|
||||||
ticker_next_y += len(ticker_content) + GAP
|
|
||||||
queued += 1
|
|
||||||
|
|
||||||
active = [
|
|
||||||
(c, hc, by, mi) for c, hc, by, mi in active if by + len(c) > camera.y
|
|
||||||
]
|
|
||||||
for k in list(noise_cache):
|
|
||||||
if k < camera.y:
|
|
||||||
del noise_cache[k]
|
|
||||||
|
|
||||||
grad_offset = (time.monotonic() * config.GRAD_SPEED) % 1.0
|
|
||||||
ticker_buf_start = len(buf)
|
|
||||||
|
|
||||||
ticker_buf, noise_cache = render_ticker_zone(
|
|
||||||
active, camera.y, camera.x, ticker_h, w, noise_cache, grad_offset
|
|
||||||
)
|
|
||||||
buf.extend(ticker_buf)
|
|
||||||
|
|
||||||
mic_excess = mic_monitor.excess
|
|
||||||
render_start = time.perf_counter()
|
|
||||||
|
|
||||||
if USE_EFFECT_CHAIN:
|
|
||||||
buf = process_effects(
|
|
||||||
buf,
|
|
||||||
w,
|
|
||||||
h,
|
|
||||||
camera.y,
|
|
||||||
ticker_h,
|
|
||||||
camera.x,
|
|
||||||
mic_excess,
|
|
||||||
grad_offset,
|
|
||||||
frame_number,
|
|
||||||
msg is not None,
|
|
||||||
items,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
buf = apply_glitch(buf, ticker_buf_start, mic_excess, w)
|
|
||||||
firehose_buf = render_firehose(items, w, fh, h)
|
|
||||||
buf.extend(firehose_buf)
|
|
||||||
|
|
||||||
if msg_overlay:
|
|
||||||
buf.extend(msg_overlay)
|
|
||||||
|
|
||||||
render_elapsed = (time.perf_counter() - render_start) * 1000
|
|
||||||
monitor = _get_display_monitor()
|
|
||||||
if monitor:
|
|
||||||
chars = sum(len(line) for line in buf)
|
|
||||||
monitor.record_effect("render", render_elapsed, chars, chars)
|
|
||||||
|
|
||||||
display.show(buf)
|
|
||||||
|
|
||||||
elapsed = time.monotonic() - t0
|
|
||||||
time.sleep(max(0, config.FRAME_DT - elapsed))
|
|
||||||
frame_number += 1
|
|
||||||
|
|
||||||
display.cleanup()
|
|
||||||
Reference in New Issue
Block a user