103 lines
3.6 KiB
Python
103 lines
3.6 KiB
Python
from engine.effects.types import (
|
|
EffectConfig,
|
|
EffectContext,
|
|
EffectPlugin,
|
|
PartialUpdate,
|
|
)
|
|
|
|
|
|
class HudEffect(EffectPlugin):
|
|
name = "hud"
|
|
config = EffectConfig(enabled=True, intensity=1.0)
|
|
supports_partial_updates = True # Enable partial update optimization
|
|
|
|
# Cache last HUD content to detect changes
|
|
_last_hud_content: tuple | None = None
|
|
|
|
def process_partial(
|
|
self, buf: list[str], ctx: EffectContext, partial: PartialUpdate
|
|
) -> list[str]:
|
|
# If full buffer requested, process normally
|
|
if partial.full_buffer:
|
|
return self.process(buf, ctx)
|
|
|
|
# If HUD rows (0, 1, 2) aren't dirty, skip processing
|
|
if partial.dirty:
|
|
hud_rows = {0, 1, 2}
|
|
dirty_hud_rows = partial.dirty & hud_rows
|
|
if not dirty_hud_rows:
|
|
return buf # Nothing for HUD to do
|
|
|
|
# Proceed with full processing
|
|
return self.process(buf, ctx)
|
|
|
|
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
|
|
result = list(buf)
|
|
|
|
# Read metrics from pipeline context (first-class citizen)
|
|
# Falls back to global monitor for backwards compatibility
|
|
metrics = ctx.get_state("metrics")
|
|
if not metrics:
|
|
# Fallback to global monitor for backwards compatibility
|
|
from engine.effects.performance import get_monitor
|
|
|
|
monitor = get_monitor()
|
|
if monitor:
|
|
stats = monitor.get_stats()
|
|
if stats and "pipeline" in stats:
|
|
metrics = stats
|
|
|
|
fps = 0.0
|
|
frame_time = 0.0
|
|
if metrics:
|
|
if "error" in metrics:
|
|
pass # No metrics available yet
|
|
elif "pipeline" in metrics:
|
|
frame_time = metrics["pipeline"].get("avg_ms", 0.0)
|
|
frame_count = metrics.get("frame_count", 0)
|
|
if frame_count > 0 and frame_time > 0:
|
|
fps = 1000.0 / frame_time
|
|
elif "avg_ms" in metrics:
|
|
# Direct metrics format
|
|
frame_time = metrics.get("avg_ms", 0.0)
|
|
frame_count = metrics.get("frame_count", 0)
|
|
if frame_count > 0 and frame_time > 0:
|
|
fps = 1000.0 / frame_time
|
|
|
|
effect_name = self.config.params.get("display_effect", "none")
|
|
effect_intensity = self.config.params.get("display_intensity", 0.0)
|
|
|
|
hud_lines = []
|
|
hud_lines.append(
|
|
f"\033[1;1H\033[38;5;46mMAINLINE DEMO\033[0m \033[38;5;245m|\033[0m \033[38;5;39mFPS: {fps:.1f}\033[0m \033[38;5;245m|\033[0m \033[38;5;208m{frame_time:.1f}ms\033[0m"
|
|
)
|
|
|
|
bar_width = 20
|
|
filled = int(bar_width * effect_intensity)
|
|
bar = (
|
|
"\033[38;5;82m"
|
|
+ "█" * filled
|
|
+ "\033[38;5;240m"
|
|
+ "░" * (bar_width - filled)
|
|
+ "\033[0m"
|
|
)
|
|
hud_lines.append(
|
|
f"\033[2;1H\033[38;5;45mEFFECT:\033[0m \033[1;38;5;227m{effect_name:12s}\033[0m \033[38;5;245m|\033[0m {bar} \033[38;5;245m|\033[0m \033[38;5;219m{effect_intensity * 100:.0f}%\033[0m"
|
|
)
|
|
|
|
# Get pipeline order from context
|
|
pipeline_order = ctx.get_state("pipeline_order")
|
|
pipeline_str = ",".join(pipeline_order) if pipeline_order else "(none)"
|
|
hud_lines.append(f"\033[3;1H\033[38;5;44mPIPELINE:\033[0m {pipeline_str}")
|
|
|
|
for i, line in enumerate(hud_lines):
|
|
if i < len(result):
|
|
result[i] = line
|
|
else:
|
|
result.append(line)
|
|
|
|
return result
|
|
|
|
def configure(self, config: EffectConfig) -> None:
|
|
self.config = config
|