83 lines
3.6 KiB
C++
83 lines
3.6 KiB
C++
#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
|