Source code for mini_arcade_core.engine.render.passes.lighting
"""
Lighting render pass implementation.
"""
from __future__ import annotations
from dataclasses import dataclass
from mini_arcade_core.backend import Backend
from mini_arcade_core.engine.render.camera import viewport_transform_for_packet
from mini_arcade_core.engine.render.context import RenderContext
from mini_arcade_core.engine.render.frame_packet import FramePacket
from mini_arcade_core.engine.render.packet import DrawOp, RenderPacket
[docs]
@dataclass
class LightingPass:
"""
Lighting Render Pass.
This pass handles scene lighting effects.
"""
name: str = "LightingPass"
[docs]
def run(
self, backend: Backend, ctx: RenderContext, packets: list[FramePacket]
):
"""Run the lighting render pass."""
for fp in packets:
if fp.is_overlay:
continue
ops = self._layer_ops(fp.packet, "lighting")
if ops is None or not ops:
continue
self._draw_ops(backend, ctx, fp.packet, ops)
@staticmethod
def _layer_ops(
packet: RenderPacket, key: str
) -> tuple[DrawOp, ...] | None:
raw = packet.meta.get("pass_ops")
if not isinstance(raw, dict):
return None
ops = raw.get(key)
if ops is None:
return tuple()
return tuple(ops)
@staticmethod
def _draw_ops(
backend: Backend,
ctx: RenderContext,
packet: RenderPacket,
ops: tuple[DrawOp, ...],
) -> None:
ctx.stats.packets += 1
ctx.stats.renderables += len(ops)
ctx.stats.draw_groups += 1
world_transform = viewport_transform_for_packet(ctx.viewport, packet)
backend.set_viewport_transform(
ctx.viewport.offset_x,
ctx.viewport.offset_y,
ctx.viewport.scale,
)
backend.render.set_clip_rect(
0,
0,
ctx.viewport.virtual_w,
ctx.viewport.virtual_h,
)
try:
backend.set_viewport_transform(
world_transform.ox,
world_transform.oy,
world_transform.s,
)
for op in ops:
op(backend)
finally:
backend.render.clear_clip_rect()
backend.clear_viewport_transform()