diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index 99e52a77..ee73a040 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -205,17 +205,20 @@ struct surfflags_t // custom opacity vec_t light_alpha; + // maxlight value for this face + vec_t maxlight; + constexpr bool needs_write() const { return no_dirt || no_shadow || no_bounce || no_minlight || no_expand || light_ignore || phong_angle || - phong_angle_concave || minlight || !qv::emptyExact(minlight_color) || light_alpha; + phong_angle_concave || minlight || !qv::emptyExact(minlight_color) || light_alpha || maxlight; } private: constexpr auto as_tuple() const { return std::tie(native, is_skip, is_hintskip, is_hint, no_dirt, no_shadow, no_bounce, no_minlight, no_expand, - light_ignore, phong_angle, phong_angle_concave, minlight, minlight_color, light_alpha); + light_ignore, phong_angle, phong_angle_concave, minlight, minlight_color, light_alpha, maxlight); } public: diff --git a/include/light/light.hh b/include/light/light.hh index 5c508314..d7a73d91 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -107,7 +107,7 @@ struct lightsurf_t const mbsp_t *bsp; const mface_t *face; /* these take precedence the values in modelinfo */ - vec_t minlight; + vec_t minlight, maxlight; qvec3d minlight_color; bool nodirt, minlightMottle; @@ -208,8 +208,11 @@ public: const dmodelh2_t *model; float lightmapscale; qvec3d offset{}; - + settings::setting_scalar minlight{this, "minlight", 0}; + // zero will apply no clamping; use lightignore instead to do that. + // above zero, this controls the clamp value on the light, default 255 + settings::setting_scalar maxlight{this, "maxlight", 0}; settings::setting_bool minlightMottle{this, "minlightMottle", false}; settings::setting_scalar shadow{this, "shadow", 0}; settings::setting_scalar shadowself{this, {"shadowself", "selfshadow"}, 0}; @@ -273,6 +276,7 @@ public: setting_scalar lightmapgamma{this, "gamma", 1.0, 0.0, 100.0, &worldspawn_group}; setting_bool addminlight{this, "addmin", false, &worldspawn_group}; setting_scalar minlight{this, {"light", "minlight"}, 0, &worldspawn_group}; + setting_scalar maxlight{this, "maxlight", 0, &worldspawn_group}; setting_color minlight_color{this, {"minlight_color", "mincolor"}, 255.0, 255.0, 255.0, &worldspawn_group}; setting_bool spotlightautofalloff{this, "spotlightautofalloff", false, &worldspawn_group}; // mxd setting_int32 compilerstyle_start{ diff --git a/light/light.cc b/light/light.cc index 18e0373c..1f688c7a 100644 --- a/light/light.cc +++ b/light/light.cc @@ -764,6 +764,9 @@ static void LoadExtendedTexinfoFlags(const fs::path &sourcefilename, const mbsp_ if (val.contains("minlight")) { flags.minlight = val.at("minlight").get(); } + if (val.contains("maxlight")) { + flags.maxlight = val.at("maxlight").get(); + } if (val.contains("minlight_color")) { flags.minlight_color = val.at("minlight_color").get(); } diff --git a/light/ltface.cc b/light/ltface.cc index b63821d6..271d6121 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -634,23 +634,35 @@ static std::unique_ptr Lightsurf_Init(const modelinfo_t *modelinfo, } lightsurf->minlightMottle = modelinfo->minlightMottle.value(); - + // minlight if (modelinfo->minlight.isChanged()) { lightsurf->minlight = modelinfo->minlight.value(); - - // Q2 uses a 0-1 range for minlight - if (bsp->loadversion->game->id == GAME_QUAKE_II) { - lightsurf->minlight *= 128.f; - - if (!modelinfo->minlightMottle.isChanged()) { - lightsurf->minlightMottle = true; - } - } } else { lightsurf->minlight = extended_flags.minlight; } + // Q2 uses a 0-1 range for minlight + if (bsp->loadversion->game->id == GAME_QUAKE_II) { + lightsurf->minlight *= 128.f; + + if (!modelinfo->minlightMottle.isChanged()) { + lightsurf->minlightMottle = true; + } + } + + // maxlight + if (modelinfo->maxlight.isChanged()) { + lightsurf->maxlight = modelinfo->maxlight.value(); + } else { + lightsurf->maxlight = extended_flags.maxlight; + } + + // Q2 uses a 0-1 range for minlight + if (bsp->loadversion->game->id == GAME_QUAKE_II) { + lightsurf->maxlight *= 128.f; + } + // minlight_color if (modelinfo->minlight_color.isChanged()) { lightsurf->minlight_color = modelinfo->minlight_color.value(); @@ -1331,7 +1343,7 @@ static void LightFace_Sky(const sun_t *sun, lightsurf_t *lightsurf, lightmapdict continue; } - qvec3d normalcontrib = sun->sunvec * value; + qvec3d normalcontrib = incoming * value; rs.pushRay(i, surfpoint, incoming, MAX_SKY_DIST, &color, &normalcontrib); } @@ -2200,17 +2212,32 @@ inline void LightFace_ScaleAndClamp(lightsurf_t *lightsurf) /* Fix any negative values */ color = qv::max(color, {0}); - /* Scale and clamp any out-of-range samples */ - color *= cfg.rangescale.value(); + // before any other scaling, apply maxlight + if (lightsurf->maxlight || cfg.maxlight.value()) { + vec_t maxcolor = qv::max(color); + // FIXME: for colored lighting, this doesn't seem to generate the right values... + vec_t maxval = (lightsurf->maxlight ? lightsurf->maxlight : cfg.maxlight.value()) * 2.0; - for (auto &c : color) { - c = pow(c / 255.0f, 1.0 / cfg.lightmapgamma.value()) * 255.0f; + if (maxcolor > maxval) { + color *= (maxval / maxcolor); + } } + /* Scale and handle gamma adjustment */ + color *= cfg.rangescale.value(); + + if (cfg.lightmapgamma.value() != 1.0) { + for (auto &c : color) { + c = pow(c / 255.0f, 1.0 / cfg.lightmapgamma.value()) * 255.0f; + } + } + + // clamp + // FIXME: should this be a brightness clamp? vec_t maxcolor = qv::max(color); - if (maxcolor > 255) { - color *= (255.0f / maxcolor); + if (maxcolor > 255.0) { + color *= (255.0 / maxcolor); } } } diff --git a/qbsp/map.cc b/qbsp/map.cc index 4afa7129..de5b9cf7 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -495,6 +495,14 @@ static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapenti flags.minlight = clamp(minlight, 0.0, 510.0); } + // handle "_maxlight" + const vec_t maxlight = entity->epairs.get_float("_maxlight"); + if (maxlight > 0) { + // CHECK: allow > 510 now that we're float? or is it not worth it since it will + // be beyond max? + flags.maxlight = clamp(maxlight, 0.0, 510.0); + } + // handle "_mincolor" { qvec3d mincolor{}; diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index d859b8e8..78a74074 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -366,6 +366,9 @@ static void WriteExtendedTexinfoFlags(void) if (tx.flags.minlight) { t["minlight"] = tx.flags.minlight; } + if (tx.flags.maxlight) { + t["maxlight"] = tx.flags.maxlight; + } if (!qv::emptyExact(tx.flags.minlight_color)) { t["minlight_color"] = tx.flags.minlight_color; }