Source code for mini_arcade_core.engine.render.effects.vignette

"""
Vignette noise screen-space post effect.
"""

# Justification: PoC code for v1.
# pylint: disable=duplicate-code

from __future__ import annotations

import random
from dataclasses import dataclass

from mini_arcade_core.backend import Backend
from mini_arcade_core.engine.render.context import RenderContext
from mini_arcade_core.engine.render.effects.base import EffectParams


[docs] @dataclass class VignetteNoiseEffect: """ Vignette + noise screen-space post effect. Simulates a vignette effect with added noise/grain. """ effect_id: str = "vignette_noise" # Justification: This is PoC code for v1. # pylint: disable=too-many-locals
[docs] def apply(self, backend: Backend, ctx: RenderContext): """Apply the Vignette + Noise effect to the current render context.""" vp = ctx.viewport x0, y0 = vp.offset_x, vp.offset_y w, h = vp.viewport_w, vp.viewport_h stack = ctx.meta.get("effects_stack") params: EffectParams = ( stack.params.get(self.effect_id, EffectParams()) if stack else EffectParams() ) intensity = max(0.0, min(1.0, params.intensity)) if intensity <= 0.0: return backend.render.set_clip_rect(x0, y0, w, h) # Vignette approximation: draw edge rectangles with increasing alpha. # Not a true radial gradient, but good enough for v1. steps = 10 max_alpha = int(110 * intensity) # subtle for i in range(steps): # thickness grows inward t = i + 1 alpha = int(max_alpha * (t / steps)) color = (0, 0, 0, alpha) # top backend.render.draw_rect(x0, y0, w, t, color=color) # bottom backend.render.draw_rect(x0, y0 + h - t, w, t, color=color) # left backend.render.draw_rect(x0, y0, t, h, color=color) # right backend.render.draw_rect(x0 + w - t, y0, t, h, color=color) # Noise: sprinkle a few pixels (or tiny 1x1 rects). # Use deterministic-ish seed per frame so it doesn't “swim” too much. frame = int(ctx.meta.get("frame_index", 0)) random.seed(frame * 1337) dots = int(200 * intensity) # tweak for _ in range(dots): px = x0 + random.randint(0, max(0, w - 1)) py = y0 + random.randint(0, max(0, h - 1)) a = random.randint(10, int(50 * intensity) + 10) backend.render.draw_rect(px, py, 1, 1, color=(255, 255, 255, a)) backend.render.clear_clip_rect()