import time import math import random from imgui_bundle import imgui class CRTFilter: def __init__(self): self.enabled = True def render(self, width: float, height: float): if not self.enabled: return draw_list = imgui.get_foreground_draw_list() # 1. Enhanced Scanlines (Horizontal) # Vary thickness and alpha for a more "analog" feel for y in range(0, int(height), 2): # Thicker/Darker every 4 pixels is_major = (y % 4 == 0) alpha = 0.08 if is_major else 0.04 thickness = 1.2 if is_major else 0.8 s_color = imgui.get_color_u32((0.0, 0.0, 0.0, alpha)) draw_list.add_line((0.0, float(y)), (float(width), float(y)), s_color, thickness) # 2. Shadow Mask (Vertical) # Simulates aperture grille / phosphor strips m_color = imgui.get_color_u32((0.0, 0.0, 0.0, 0.05)) for x in range(0, int(width), 3): draw_list.add_line((float(x), 0.0), (float(x), float(height)), m_color, 1.0) # 3. Enhanced Curved Vignette / Tube Curvature # Multiple rounded rectangles with increasing thickness and alpha v_steps = 20 for i in range(v_steps): # Exponential alpha for smoother falloff alpha = (i / v_steps) ** 3.0 * 0.25 v_color = imgui.get_color_u32((0.0, 0.0, 0.0, alpha)) # Inset and rounding grow to simulate tube curvature inset = (v_steps - i) * 4.5 rounding = 60.0 + (v_steps - i) * 8.0 thickness = 15.0 if width > inset * 2.0 and height > inset * 2.0: draw_list.add_rect( (inset, inset), (width - inset, height - inset), v_color, rounding, 0, thickness ) # 4. Subtle Random Noise / Static t = time.time() for _ in range(40): nx = random.uniform(0.0, width) ny = random.uniform(0.0, height) # Flickering noise n_alpha = random.uniform(0.01, 0.04) * (0.8 + 0.2 * math.sin(t * 60.0)) n_color = imgui.get_color_u32((1.0, 1.0, 1.0, n_alpha)) draw_list.add_rect_filled((nx, ny), (nx + 1.2, ny + 1.2), n_color) class StatusFlicker: def get_alpha(self) -> float: # Modulate between 0.7 and 1.0 using sin wave return 0.85 + 0.15 * math.sin(time.time() * 20.0) class AlertPulsing: def __init__(self): self.active = False def update(self, status: str): self.active = status.lower().startswith("error") def render(self, width: float, height: float): if not self.active: return draw_list = imgui.get_foreground_draw_list() # sin(t) is between -1 and 1 # scale to 0 to 1: (sin(t) + 1) / 2 # multiply by (0.2 - 0.05) = 0.15 and add 0.05 alpha = 0.05 + 0.15 * ((math.sin(time.time() * 4.0) + 1.0) / 2.0) color = imgui.get_color_u32((1.0, 0.0, 0.0, alpha)) draw_list.add_rect((0.0, 0.0), (width, height), color, 0.0, 0, 10.0)