feat(lighting): corba additive separada al config

This commit is contained in:
JailDesigner committed 2026-05-13 17:53:32 +02:00
1 parent 771ff1f6cd
commit dacc4a9909
7 files changed
+100 -34

No files matched your search

+40 -14
View File
@@ -26,9 +26,9 @@ namespace Lighting {
return buf_;
}
// Configuració global, inicialitzada amb els defaults compilats.
// loadConfig() la reemplaça si troba el fitxer.
auto activeConfig() -> GradientConfig& {
// Corba activa del mode subtractive. loadConfig() la reemplaça
// si troba el bloc `gradient:` al YAML.
auto activeSubtractiveConfig() -> GradientConfig& {
static GradientConfig cfg_{
.inner_ratio = Defaults::Lighting::INNER_RATIO,
.mid_ratio = Defaults::Lighting::MID_RATIO,
@@ -39,6 +39,22 @@ namespace Lighting {
return cfg_;
}
// Corba activa del mode additive. Defaults baixos a propòsit:
// en additive la intensitat és l'alfa del color afegit, així
// que valors petits (0.05..0.15) donen el "halo subtil" que
// sol voler-se. loadConfig() la reemplaça si troba el bloc
// `gradient_additive:` al YAML.
auto activeAdditiveConfig() -> GradientConfig& {
static GradientConfig cfg_{
.inner_ratio = Defaults::Lighting::INNER_RATIO_ADDITIVE,
.mid_ratio = Defaults::Lighting::MID_RATIO_ADDITIVE,
.inner_intensity = Defaults::Lighting::INNER_INTENSITY_ADDITIVE,
.mid_intensity = Defaults::Lighting::MID_INTENSITY_ADDITIVE,
.outer_intensity = Defaults::Lighting::OUTER_INTENSITY_ADDITIVE,
};
return cfg_;
}
auto activeFlicker() -> FlickerConfig& {
static FlickerConfig fc_{
.wave_amplitude_px = Defaults::Lighting::FLICKER_WAVE_AMPLITUDE_PX,
@@ -232,9 +248,22 @@ namespace Lighting {
} // namespace
auto config() -> const GradientConfig& {
return activeConfig();
return activeSubtractiveConfig();
}
namespace {
// Llegeix els 5 camps de `GradientConfig` d'un node YAML — qualsevol
// camp absent conserva el valor compilat dels defaults. Compartit
// entre els blocs `gradient:` i `gradient_additive:`.
void readGradient(const fkyaml::node& g, GradientConfig& cfg) {
readField(g, "inner_ratio", cfg.inner_ratio);
readField(g, "mid_ratio", cfg.mid_ratio);
readField(g, "inner_intensity", cfg.inner_intensity);
readField(g, "mid_intensity", cfg.mid_intensity);
readField(g, "outer_intensity", cfg.outer_intensity);
}
} // namespace
void loadConfig(const std::string& yaml_path) {
auto bytes = Resource::Helper::loadFile(yaml_path);
if (bytes.empty()) {
@@ -246,13 +275,10 @@ namespace Lighting {
const auto* end = begin + bytes.size();
auto yaml = fkyaml::node::deserialize(begin, end);
if (yaml.contains("gradient")) {
const auto& g = yaml["gradient"];
auto& cfg = activeConfig();
readField(g, "inner_ratio", cfg.inner_ratio);
readField(g, "mid_ratio", cfg.mid_ratio);
readField(g, "inner_intensity", cfg.inner_intensity);
readField(g, "mid_intensity", cfg.mid_intensity);
readField(g, "outer_intensity", cfg.outer_intensity);
readGradient(yaml["gradient"], activeSubtractiveConfig());
}
if (yaml.contains("gradient_additive")) {
readGradient(yaml["gradient_additive"], activeAdditiveConfig());
}
if (yaml.contains("flicker")) {
const auto& f = yaml["flicker"];
@@ -285,7 +311,7 @@ namespace Lighting {
if (lum.size() != TOTAL) { lum.resize(TOTAL); }
std::ranges::fill(lum, room);
const auto& cfg = activeConfig();
const auto& cfg = activeSubtractiveConfig();
const auto& fc = activeFlicker();
const float T_S = static_cast<float>(SDL_GetTicks()) / 1000.0F;
for (const auto& e : emitters) {
@@ -303,7 +329,7 @@ namespace Lighting {
// canvas, sense buffer intermig.
void applyAdditive(std::uint32_t* canvas, int width, int height, std::uint8_t room, std::span<const Emitter> emitters) {
darkenCanvas(canvas, width, height, room);
const auto& cfg = activeConfig();
const auto& cfg = activeAdditiveConfig();
const auto& fc = activeFlicker();
const float T_S = static_cast<float>(SDL_GetTicks()) / 1000.0F;
for (const auto& e : emitters) {
@@ -327,7 +353,7 @@ namespace Lighting {
const std::uint8_t ROOM = toByte(room_light);
if (ROOM == 255 && emitters.empty()) { return; }
if (mode == Mode::Additive) {
if (mode == Mode::ADDITIVE) {
applyAdditive(canvas, width, height, ROOM, emitters);
} else {
applySubtractive(canvas, width, height, ROOM, emitters);
+14 -3
View File
@@ -33,6 +33,14 @@
// inner_ratio..mid_ratio → mid_intensity
// mid_ratio..1.0 → outer_intensity
//
// La corba viu en dos blocs separats al YAML perquè la mateixa escala
// 0..1 té significats molt diferents per mode:
// `gradient:` → corba del mode subtractive (1.0 = "no fosqueix")
// `gradient_additive:` → corba del mode additive (1.0 = "afegeix
// el color sencer i satura"). Es vol molt més
// baixa per a no inundar la sala de color.
// Cada mode llegeix la seva pròpia corba — no es comparteixen valors.
//
// Combinació entre emissors:
// SUBTRACTIVE → per a cada píxel es pren el màxim de la intensitat
// aportada per cada emissor que el solapa (no se sumen intensitats).
@@ -45,8 +53,8 @@ namespace Lighting {
// Mode de composició. La sala el selecciona via `lighting.mode:
// additive | subtractive` (default subtractive si manca, retrocompat).
enum class Mode : std::uint8_t {
Subtractive,
Additive,
SUBTRACTIVE,
ADDITIVE,
};
// Color emès. Default blanc (sense modificació quan s'usa en mode
@@ -104,7 +112,10 @@ namespace Lighting {
// simplement reemplaça la configuració activa.
void loadConfig(const std::string& yaml_path);
// Configuració activa (per a debug/inspectors). Inicialitzada amb els
// Configuració activa (per a debug/inspectors). Retorna sempre la
// corba subtractive — la corba additive viu en paral·lel al cpp i,
// si algun dia es necessita inspeccionar des de fora, caldrà afegir
// una variant `configAdditive()`. Inicialitzada amb els
// Defaults::Lighting fins que loadConfig() es crida.
[[nodiscard]] auto config() -> const GradientConfig&;
+3 -3
View File
@@ -73,7 +73,7 @@ namespace Map {
// d'una sala anterior.
void loadLightingBlock(const fkyaml::node& yaml) {
g_room_emitters.clear();
lighting_mode = Lighting::Mode::Subtractive;
lighting_mode = Lighting::Mode::SUBTRACTIVE;
if (!yaml.contains("lighting")) { return; }
const auto& lighting = yaml["lighting"];
if (lighting.contains("level")) {
@@ -82,9 +82,9 @@ namespace Map {
if (lighting.contains("mode")) {
const auto MODE_STR = lighting["mode"].get_value<std::string>();
if (MODE_STR == "additive") {
lighting_mode = Lighting::Mode::Additive;
lighting_mode = Lighting::Mode::ADDITIVE;
} else if (MODE_STR == "subtractive") {
lighting_mode = Lighting::Mode::Subtractive;
lighting_mode = Lighting::Mode::SUBTRACTIVE;
} else {
Log::warn("Map", "lighting.mode '{}' desconegut — s'usa subtractive", MODE_STR);
}
+1 -1
View File
@@ -69,7 +69,7 @@ namespace Map {
// Veure el comentari de `core/rendering/lighting.hpp` per a la
// semàntica de cada mode. En subtractive, els colors dels emissors
// s'ignoren — el camí és el de sempre.
inline Lighting::Mode lighting_mode = Lighting::Mode::Subtractive;
inline Lighting::Mode lighting_mode = Lighting::Mode::SUBTRACTIVE;
// Override d'emissor declarat al bloc opcional `lighting.emitters.<tipus>`
// de la sala. Tres formes acceptades al YAML:
+13
View File
@@ -111,11 +111,24 @@ namespace Defaults {
// fitxer falta o li manca alguna clau. La forma final (3 anells) es
// descriu al YAML; veure `Lighting::GradientConfig` per a la semàntica.
namespace Lighting {
// Defaults del gradient subtractive (mode històric). Les
// intensitats són multiplicadors 0..1 que es multipliquen sobre
// el píxel: 1.0 = no toca, 0.0 = negre.
constexpr float INNER_RATIO = 0.8F;
constexpr float MID_RATIO = 0.9F;
constexpr float INNER_INTENSITY = 1.0F;
constexpr float MID_INTENSITY = 0.9F;
constexpr float OUTER_INTENSITY = 0.8F;
// Defaults del gradient additive. Les intensitats són "alfa"
// del color afegit (0..1): 1.0 = afegeix el color sencer i
// satura, 0.0 = no afegeix res. Valors baixos a propòsit perquè
// l'additive es nota fort molt fàcilment — només un toc de tint
// cromàtic al voltant de l'emissor.
constexpr float INNER_RATIO_ADDITIVE = 0.5F;
constexpr float MID_RATIO_ADDITIVE = 0.85F;
constexpr float INNER_INTENSITY_ADDITIVE = 0.15F;
constexpr float MID_INTENSITY_ADDITIVE = 0.10F;
constexpr float OUTER_INTENSITY_ADDITIVE = 0.05F;
// Nivell d'il·luminació de sala per defecte. Una sala sense la
// clau `light_level` queda totalment il·luminada (com hui).
constexpr float ROOM_LIGHT_DEFAULT = 1.0F;