Files
aee-arcade/source/core/rendering/lighting.hpp
T

83 lines
3.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include <cstdint>
#include <span>
#include <string>
// Sistema d'il·luminació CPU. Treballa sobre el mateix canvas ARGB del
// joc (320×240) que tot el pipeline de render: després que GameScene
// haja pintat tilemap, paint layer, sombres i actors, una pasada final
// multiplica cada píxel del canvas per un factor de luminància 0..1
// derivat de la combinació de "llum de la sala" + cercles emissors al
// voltant de certes entitats.
//
// Forma de cada emissor (radial, 3 anells configurables al fitxer
// data/config/lighting.yaml; veure `GradientConfig`):
// 0..inner_ratio del radi → inner_intensity
// inner_ratio..mid_ratio → mid_intensity
// mid_ratio..1.0 → outer_intensity
// fora del radi → light_level de la sala
//
// Combinació entre emissors: per a cada píxel es pren el màxim del
// llum de sala i de la intensitat aportada per cada emissor que el
// solapa — no se "sumen" intensitats. Coherent amb la idea de "centre
// 1.0": el píxel que cau dins de qualsevol nucli no s'enfosqueix.
namespace Lighting {
// Posició al canvas (en píxels, mateixa unitat que la resta del
// motor) i radi efectiu de l'emissor. El centre és el del sprite
// visible: és l'entitat qui sap on cau (veure `Entity::getLightCenter`).
// `flicker` activa la modulació del radi per frame; `seed` és un
// identificador estable per emissor (no canvia amb la posició) del
// qual es deriva la fase del flicker — així els emissors mòbils
// mantenen un patró propi que no "deriva" pel moviment.
struct Emitter {
float cx{0.0F};
float cy{0.0F};
int radius{0};
int seed{0};
bool flicker{false};
};
// Forma del gradient. Compartida per tots els emissors per evitar
// duplicar la corba a cada YAML d'entitat. Càrrega via loadConfig.
struct GradientConfig {
float inner_ratio{0.8F};
float mid_ratio{0.9F};
float inner_intensity{1.0F};
float mid_intensity{0.9F};
float outer_intensity{0.8F};
};
// Paràmetres del flicker per a emissors amb `flicker=true`. La
// forma final del radi és la suma d'una sinusoide "respiració"
// (wave_*) i una sinusoide secundària de freqüència més alta
// (noise_*) que aporta la sensació d'inquietud. Les fases es
// deriven de la posició de cada emissor — sense estat per emissor.
struct FlickerConfig {
float wave_amplitude_px{2.0F};
float wave_frequency_hz{3.0F};
float noise_amplitude_px{1.0F};
float noise_frequency_hz{7.0F};
};
// Llegeix `yaml_path` (data/config/lighting.yaml) i pobla la
// configuració global. Qualsevol clau absent cau als Defaults::Lighting.
// No es crida més d'una vegada en un run normal; tornar-la a cridar
// simplement reemplaça la configuració activa.
void loadConfig(const std::string& yaml_path);
// Configuració activa (per a debug/inspectors). Inicialitzada amb els
// Defaults::Lighting fins que loadConfig() es crida.
[[nodiscard]] auto config() -> const GradientConfig&;
// Aplica la pasada d'il·luminació al canvas in-place. `room_light`
// és l'atenuació base de la sala (0..1, 1 = sense atenuació). El
// span d'emissors pot ser buit — en aquest cas tota la sala queda
// multiplicada per `room_light`. Aquesta funció no fa cap allocació
// si es crida amb la mateixa mida de canvas múltiples cops: manté
// un buffer intern reutilitzable.
void apply(std::uint32_t* canvas, int width, int height, float room_light, std::span<const Emitter> emitters);
} // namespace Lighting