feat(core): add Camera abstraction for viewport scrolling
- Add Camera class with modes: vertical, horizontal, omni, floating - Refactor scroll.py and demo to use Camera abstraction - Add vis_offset for horizontal scrolling support - Add camera_x to EffectContext for effects - Add pygame window resize handling - Add HUD effect plugin for demo mode - Add --demo flag to run demo mode - Add tests for Camera and vis_offset
This commit is contained in:
@@ -352,10 +352,11 @@ def pick_effects_config():
|
||||
|
||||
|
||||
def run_demo_mode():
|
||||
"""Run demo mode - showcases effects with real content and pygame display."""
|
||||
"""Run demo mode - showcases effects and camera modes with real content."""
|
||||
import random
|
||||
|
||||
from engine import config
|
||||
from engine.camera import Camera, CameraMode
|
||||
from engine.display import DisplayRegistry
|
||||
from engine.effects import (
|
||||
EffectContext,
|
||||
@@ -409,7 +410,6 @@ def run_demo_mode():
|
||||
pool = list(items)
|
||||
seen = set()
|
||||
active = []
|
||||
scroll_cam = 0
|
||||
ticker_next_y = 0
|
||||
noise_cache = {}
|
||||
scroll_motion_accum = 0.0
|
||||
@@ -418,6 +418,8 @@ def run_demo_mode():
|
||||
GAP = 3
|
||||
scroll_step_interval = calculate_scroll_step(config.SCROLL_DUR, h)
|
||||
|
||||
camera = Camera.vertical(speed=1.0)
|
||||
|
||||
effects_to_demo = ["noise", "fade", "glitch", "firehose"]
|
||||
effect_idx = 0
|
||||
effect_name = effects_to_demo[effect_idx]
|
||||
@@ -425,12 +427,22 @@ def run_demo_mode():
|
||||
current_intensity = 0.0
|
||||
ramping_up = True
|
||||
|
||||
print(" \033[38;5;82mStarting effect demo...\033[0m")
|
||||
camera_modes = [
|
||||
(CameraMode.VERTICAL, "vertical"),
|
||||
(CameraMode.HORIZONTAL, "horizontal"),
|
||||
(CameraMode.OMNI, "omni"),
|
||||
(CameraMode.FLOATING, "floating"),
|
||||
]
|
||||
camera_mode_idx = 0
|
||||
camera_start_time = time.time()
|
||||
|
||||
print(" \033[38;5;82mStarting effect & camera demo...\033[0m")
|
||||
print(" \033[38;5;245mPress Ctrl+C to exit\033[0m\n")
|
||||
|
||||
try:
|
||||
while True:
|
||||
elapsed = time.time() - effect_start_time
|
||||
camera_elapsed = time.time() - camera_start_time
|
||||
duration = config.DEMO_EFFECT_DURATION
|
||||
|
||||
if elapsed >= duration:
|
||||
@@ -441,6 +453,13 @@ def run_demo_mode():
|
||||
current_intensity = 0.0
|
||||
ramping_up = True
|
||||
|
||||
if camera_elapsed >= duration * 2:
|
||||
camera_mode_idx = (camera_mode_idx + 1) % len(camera_modes)
|
||||
mode, mode_name = camera_modes[camera_mode_idx]
|
||||
camera = Camera(mode=mode, speed=1.0)
|
||||
camera_start_time = time.time()
|
||||
camera_elapsed = 0
|
||||
|
||||
progress = elapsed / duration
|
||||
if ramping_up:
|
||||
current_intensity = progress
|
||||
@@ -458,18 +477,21 @@ def run_demo_mode():
|
||||
|
||||
hud_effect = registry.get("hud")
|
||||
if hud_effect:
|
||||
hud_effect.config.params["display_effect"] = effect_name
|
||||
mode_name = camera_modes[camera_mode_idx][1]
|
||||
hud_effect.config.params["display_effect"] = (
|
||||
f"{effect_name} / {mode_name}"
|
||||
)
|
||||
hud_effect.config.params["display_intensity"] = current_intensity
|
||||
|
||||
scroll_motion_accum += config.FRAME_DT
|
||||
while scroll_motion_accum >= scroll_step_interval:
|
||||
scroll_motion_accum -= scroll_step_interval
|
||||
scroll_cam += 1
|
||||
camera.update(config.FRAME_DT)
|
||||
|
||||
from engine.effects import next_headline
|
||||
from engine.render import make_block
|
||||
while ticker_next_y < camera.y + h + 10 and len(active) < 50:
|
||||
from engine.effects import next_headline
|
||||
from engine.render import make_block
|
||||
|
||||
while ticker_next_y < scroll_cam + h + 10:
|
||||
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))
|
||||
@@ -478,10 +500,10 @@ def run_demo_mode():
|
||||
active = [
|
||||
(c, hc, by, mi)
|
||||
for c, hc, by, mi in active
|
||||
if by + len(c) > scroll_cam
|
||||
if by + len(c) > camera.y
|
||||
]
|
||||
for k in list(noise_cache):
|
||||
if k < scroll_cam:
|
||||
if k < camera.y:
|
||||
del noise_cache[k]
|
||||
|
||||
grad_offset = (time.time() * config.GRAD_SPEED) % 1.0
|
||||
@@ -489,7 +511,13 @@ def run_demo_mode():
|
||||
from engine.layers import render_ticker_zone
|
||||
|
||||
buf, noise_cache = render_ticker_zone(
|
||||
active, scroll_cam, h, w, noise_cache, grad_offset
|
||||
active,
|
||||
scroll_cam=camera.y,
|
||||
camera_x=camera.x,
|
||||
ticker_h=h,
|
||||
w=w,
|
||||
noise_cache=noise_cache,
|
||||
grad_offset=grad_offset,
|
||||
)
|
||||
|
||||
from engine.layers import render_firehose
|
||||
@@ -500,8 +528,9 @@ def run_demo_mode():
|
||||
ctx = EffectContext(
|
||||
terminal_width=w,
|
||||
terminal_height=h,
|
||||
scroll_cam=scroll_cam,
|
||||
scroll_cam=camera.y,
|
||||
ticker_height=h,
|
||||
camera_x=camera.x,
|
||||
mic_excess=0.0,
|
||||
grad_offset=grad_offset,
|
||||
frame_number=frame_number,
|
||||
|
||||
Reference in New Issue
Block a user