From 7d881768faca0074bf4490261278ea568ab9b2cf Mon Sep 17 00:00:00 2001 From: Jonathan Date: Mon, 4 Sep 2023 02:51:20 -0400 Subject: [PATCH] Revert "Revert "reduce memory usage by only storing VPLs when we need to, and only once"" This reverts commit 2e0e23622bddb533830168dd8e77cb49fe6395a9. Disable rescale by default on sky faces. Light is now in control of rescales' default value. Multiply omni light faces by 0.5 to better match qrad3 Remove some asserts to increase perf --- include/common/bspfile.hh | 2 +- include/light/bounce.hh | 1 - include/light/light.hh | 3 + include/light/surflight.hh | 41 ++++---- light/bounce.cc | 64 ++++++------- light/light.cc | 10 +- light/ltface.cc | 138 +++++++++++++++----------- light/surflight.cc | 192 ++++++++++++++++++++----------------- qbsp/map.cc | 5 +- qbsp/writebsp.cc | 4 +- 10 files changed, 257 insertions(+), 203 deletions(-) diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index e12b7770..89980982 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -152,7 +152,7 @@ struct surfflags_t // if true, rescales any surface light emitted by these brushes to emit 50% light at 90 degrees from the surface // normal if false, use a more natural angle falloff of 0% at 90 degrees - bool surflight_rescale = true; + std::optional surflight_rescale; // override surface lighting style std::optional surflight_style; diff --git a/include/light/bounce.hh b/include/light/bounce.hh index 268e12d0..deba5c9d 100644 --- a/include/light/bounce.hh +++ b/include/light/bounce.hh @@ -29,5 +29,4 @@ struct mbsp_t; // public functions void ResetBounce(); -const std::vector &BounceLights(); void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp); diff --git a/include/light/light.hh b/include/light/light.hh index 8a9735b8..f5f13905 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -143,6 +143,9 @@ struct lightsurf_t std::unique_ptr intersection_stream; lightmapdict_t lightmapsByStyle; + + // surface light stuff + std::unique_ptr vpl; }; /* debug */ diff --git a/include/light/surflight.hh b/include/light/surflight.hh index a0feac75..d104ac5f 100644 --- a/include/light/surflight.hh +++ b/include/light/surflight.hh @@ -39,33 +39,40 @@ struct surfacelight_t { qvec3d pos; qvec3f surfnormal; - /** - * disables use of the surfnormal. We set this to true on sky surface lights, - * to avoid black seams on geometry meeting the sky - */ - bool omnidirectional; - std::vector points; - std::vector leaves; - - // Surface light settings... - float intensity; // Surface light strength for each point - float totalintensity; // Total surface light strength - qvec3d color; // Surface color + size_t points_before_culling; // Estimated visible AABB culling aabb3d bounds; - int32_t style; - - // rescale faces to account for perpendicular lights - bool rescale; std::optional minlight_scale; + + std::vector points; + std::vector leaves; + + // Surface light settings... + struct per_style_t + { + bool bounce = false; // whether this is a direct or indirect emission + /** + * disables use of the surfnormal. We set this to true on sky surface lights, + * to avoid black seams on geometry meeting the sky + */ + bool omnidirectional = false; + // rescale faces to account for perpendicular lights + bool rescale = false; + int32_t style = 0; // style ID + float intensity = 0; // Surface light strength for each point + float totalintensity = 0; // Total surface light strength + qvec3d color; // Surface color }; + // Light data per style + std::vector styles; +}; + class light_t; void ResetSurflight(); -std::vector &GetSurfaceLights(); size_t GetSurflightPoints(); std::optional> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face); const std::vector &SurfaceLightsForFaceNum(int facenum); diff --git a/light/bounce.cc b/light/bounce.cc index ff0548a9..57a7256e 100644 --- a/light/bounce.cc +++ b/light/bounce.cc @@ -39,13 +39,10 @@ #include #include -std::mutex bouncelights_lock; -static std::vector bouncelights; static std::atomic_size_t bouncelightpoints; void ResetBounce() { - bouncelights.clear(); bouncelightpoints = 0; } @@ -88,16 +85,14 @@ static bool Face_ShouldBounce(const mbsp_t *bsp, const mface_t *face) return true; } -static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, const mface_t *face, - qvec3d texture_color, int32_t style, const std::vector &points, const polylib::winding_t &winding, +static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, lightsurf_t &surf, + qvec3d texture_color, int32_t style, std::vector &points, const vec_t &area, const qvec3d &facenormal, const qvec3d &facemidpoint) { - if (!Face_IsEmissive(bsp, face)) { + if (!Face_IsEmissive(bsp, surf.face)) { return; } - bouncelightpoints += points.size(); - // Calculate emit color and intensity... // Calculate intensity... @@ -107,50 +102,48 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys & return; } - // Normalize color... - if (intensity > 1.0) { - texture_color *= 1.0 / intensity; - } + // Normalize color... + if (intensity > 1.0) { + texture_color *= 1.0 / intensity; + } + + if (!surf.vpl) { + auto &l = surf.vpl = std::make_unique(); // Sanity checks... Q_assert(!points.empty()); // Add surfacelight... - surfacelight_t l; - l.surfnormal = facenormal; - l.omnidirectional = false; - l.points = points; - l.style = style; + l->surfnormal = facenormal; + l->points = std::move(points); // Init bbox... if (light_options.visapprox.value() == visapprox_t::RAYS) { - l.bounds = EstimateVisibleBoundsAtPoint(facemidpoint); + l->bounds = EstimateVisibleBoundsAtPoint(facemidpoint); } - for (auto &pt : l.points) { + for (auto &pt : l->points) { if (light_options.visapprox.value() == visapprox_t::VIS) { - l.leaves.push_back(Light_PointInLeaf(bsp, pt)); + l->leaves.push_back(Light_PointInLeaf(bsp, pt)); } else if (light_options.visapprox.value() == visapprox_t::RAYS) { - l.bounds += EstimateVisibleBoundsAtPoint(pt); + l->bounds += EstimateVisibleBoundsAtPoint(pt); } } - l.pos = facemidpoint; + l->pos = facemidpoint; + } // Store surfacelight settings... - l.totalintensity = intensity * area; - l.intensity = l.totalintensity / l.points.size(); - l.color = texture_color; - - // Store light... - std::unique_lock lck{bouncelights_lock}; - bouncelights.push_back(l); - } - -const std::vector &BounceLights() { - return bouncelights; + auto &l = surf.vpl; + auto &setting = l->styles.emplace_back(); + setting.bounce = true; + setting.style = style; + setting.totalintensity = intensity * area; + setting.intensity = setting.totalintensity / l->points.size(); + setting.color = texture_color; } +} static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const mbsp_t *bsp, const mface_t &face) { @@ -245,8 +238,7 @@ static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const m } for (auto &style : emitcolors) { - MakeBounceLight( - bsp, cfg, &face, style.second, style.first, points, winding, area, facenormal, facemidpoint); + MakeBounceLight(bsp, cfg, surf, style.second, style.first, points, area, facenormal, facemidpoint); } } @@ -256,5 +248,5 @@ void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp) logging::parallel_for_each(bsp->dfaces, [&](const mface_t &face) { MakeBounceLightsThread(cfg, bsp, face); }); - logging::print("{} bounce lights created, with {} points\n", bouncelights.size(), bouncelightpoints); + // logging::print("{} bounce lights created, with {} points\n", bouncelights.size(), bouncelightpoints); } diff --git a/light/light.cc b/light/light.cc index 1d3d9bca..ed7130d3 100644 --- a/light/light.cc +++ b/light/light.cc @@ -745,11 +745,15 @@ static void SaveLightmapSurfaces(mbsp_t *bsp) SaveLightmapSurface(bsp, f, nullptr, nullptr, surf.get(), surf->extents, surf->vanilla_extents); SaveLightmapSurface(bsp, f, &faces_sup[i], nullptr, surf.get(), surf->extents, surf->extents); } - - light_surfaces[i].reset(); }); } +void ClearLightmapSurfaces(mbsp_t *bsp) +{ + logging::funcheader(); + logging::parallel_for(static_cast(0), bsp->dfaces.size(), [&bsp](size_t i) { light_surfaces[i].reset(); }); +} + static void FindModelInfo(const mbsp_t *bsp) { Q_assert(modelinfo.size() == 0); @@ -1595,6 +1599,8 @@ int light_main(int argc, const char **argv) LightGrid(&bspdata); + ClearLightmapSurfaces(&std::get(bspdata.bsp)); + // invalidate normals bspdata.bspx.entries.erase("FACENORMALS"); diff --git a/light/ltface.cc b/light/ltface.cc index 3786afac..58fbd93c 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -26,7 +26,6 @@ #include #include #include -#include #include // for facesup_t #include @@ -1018,13 +1017,22 @@ constexpr vec_t SQR(vec_t x) } // CHECK: naming? why clamp*min*? -constexpr void Light_ClampMin(lightsample_t &sample, const vec_t light, const qvec3d &color) +constexpr bool Light_ClampMin(lightsample_t &sample, const vec_t light, const qvec3d &color) { + bool changed = false; + for (int i = 0; i < 3; i++) { - sample.color[i] = std::max(sample.color[i], (float)(color[i] * (light / 255.0f))); + float c = (float)(color[i] * (light / 255.0f)); + + if (c > sample.color[i]) { + sample.color[i] = c; + changed = true; } } + return changed; +} + constexpr vec_t fraction(const vec_t &min, const vec_t &val, const vec_t &max) { if (val >= max) @@ -1668,14 +1676,13 @@ static void LightFace_Min(const mbsp_t *bsp, const mface_t *face, const qvec3d & } if (cfg.addminlight.value()) { sample.color += color * (value / 255.0); + hit = true; } else { if (lightsurf->minlightMottle) { value += Mottle(surf_sample.point); } - Light_ClampMin(sample, value, color); + hit = Light_ClampMin(sample, value, color) || hit; } - - hit = true; } if (hit) { @@ -1751,11 +1758,11 @@ static void LightFace_LocalMin( cfg, lightsurf->samples[i].occlusion, entity.get(), 0.0 /* TODO: pass distance */, lightsurf); if (cfg.addminlight.value()) { sample.color += entity->color.value() * (value / 255.0); + hit = true; } else { - Light_ClampMin(sample, value, entity->color.value()); + hit = Light_ClampMin(sample, value, entity->color.value()) || hit; } - hit = true; total_light_ray_hits++; } @@ -1898,7 +1905,7 @@ static void LightFace_DebugMottle(const mbsp_t *bsp, const lightsurf_t *lightsur } // mxd. Surface light falloff. Returns color in [0,255] -inline qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg, const float &surf_scale, +constexpr qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg, const float &surf_scale, const float &intensity, const qvec3d &color, const float &dist, const float &hotspot_clamp) { // Exponential falloff @@ -1911,25 +1918,25 @@ inline qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg, con // dir: vpl -> sample point direction // mxd. returns color in [0,255] -inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const surfacelight_t *vpl, const qvec3f &dir, - const float dist, const qvec3f &normal, bool use_normal, const vec_t &standard_scale, const vec_t &sky_scale, - const float &hotspot_clamp) +inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const surfacelight_t &vpl, + const surfacelight_t::per_style_t &vpl_settings, const qvec3f &dir, const float dist, const qvec3f &normal, + bool use_normal, const vec_t &standard_scale, const vec_t &sky_scale, const float &hotspot_clamp) { qvec3f result; float dotProductFactor = 1.0f; - float dp1 = qv::dot(vpl->surfnormal, dir); + float dp1 = qv::dot(vpl.surfnormal, dir); const qvec3f sp_vpl = dir * -1.0f; float dp2 = use_normal ? qv::dot(sp_vpl, normal) : 1.0f; - if (!vpl->omnidirectional) { + if (!vpl_settings.omnidirectional) { if (dp1 < -LIGHT_ANGLE_EPSILON) return {0}; // sample point behind vpl if (dp2 < -LIGHT_ANGLE_EPSILON) return {0}; // vpl behind sample face // Rescale a bit to brighten the faces nearly-perpendicular to the surface light plane... - if (vpl->rescale) { + if (vpl_settings.rescale) { dp1 = 0.5f + dp1 * 0.5f; dp2 = 0.5f + dp2 * 0.5f; } @@ -1937,25 +1944,25 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur dotProductFactor = dp1 * dp2; } else { // used for sky face surface lights - dotProductFactor = dp2; + dotProductFactor = dp2 * 0.5f; } dotProductFactor = std::max(0.0f, dotProductFactor); // Get light contribution - result = SurfaceLight_ColorAtDist( - cfg, vpl->omnidirectional ? sky_scale : standard_scale, vpl->intensity, vpl->color, dist, hotspot_clamp); + result = SurfaceLight_ColorAtDist(cfg, vpl_settings.omnidirectional ? sky_scale : standard_scale, + vpl_settings.intensity, vpl_settings.color, dist, hotspot_clamp); // Apply angle scale const qvec3f resultscaled = result * dotProductFactor; - Q_assert(!std::isnan(resultscaled[0]) && !std::isnan(resultscaled[1]) && !std::isnan(resultscaled[2])); + //Q_assert(!std::isnan(resultscaled[0]) && !std::isnan(resultscaled[1]) && !std::isnan(resultscaled[2])); return resultscaled; } static bool // mxd -SurfaceLight_SphereCull( - const surfacelight_t *vpl, const lightsurf_t *lightsurf, const vec_t &bouncelight_gate, const float &hotspot_clamp) +SurfaceLight_SphereCull(const surfacelight_t *vpl, const lightsurf_t *lightsurf, + const surfacelight_t::per_style_t &vpl_settings, const vec_t &bouncelight_gate, const float &hotspot_clamp) { if (light_options.visapprox.value() == visapprox_t::RAYS && vpl->bounds.disjoint(lightsurf->extents.bounds, 0.001)) { @@ -1967,17 +1974,16 @@ SurfaceLight_SphereCull( const float dist = qv::length(dir) + lightsurf->extents.radius; // Get light contribution - const qvec3f color = - SurfaceLight_ColorAtDist(cfg, vpl->omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(), - vpl->totalintensity, vpl->color, dist, hotspot_clamp); + const qvec3f color = SurfaceLight_ColorAtDist(cfg, + vpl_settings.omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(), + vpl_settings.totalintensity, vpl_settings.color, dist, hotspot_clamp); return qv::gate(color, (float)bouncelight_gate); } static void // mxd -LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps, - const std::vector &surface_lights, const vec_t &standard_scale, const vec_t &sky_scale, - const float &hotspot_clamp) +LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps, bool bounce, + const vec_t &standard_scale, const vec_t &sky_scale, const float &hotspot_clamp) { const settings::worldspawn_keys &cfg = *lightsurf->cfg; const float surflight_gate = 0.01f; @@ -1987,9 +1993,21 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t return; } - for (const surfacelight_t &vpl : surface_lights) { - if (SurfaceLight_SphereCull(&vpl, lightsurf, surflight_gate, hotspot_clamp)) + for (const auto &surf_ptr : LightSurfaces()) { + + if (!surf_ptr || !surf_ptr->vpl) { + // didn't emit anthing continue; + } + + auto &vpl = *surf_ptr->vpl.get(); + + for (const auto &vpl_setting : surf_ptr->vpl->styles) { + + if (vpl_setting.bounce != bounce) + continue; + else if (SurfaceLight_SphereCull(&vpl, lightsurf, vpl_setting, surflight_gate, hotspot_clamp)) + continue; raystream_occlusion_t &rs = *lightsurf->occlusion_stream; @@ -2025,8 +2043,8 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t dir /= dist; } - const qvec3f indirect = GetSurfaceLighting( - cfg, &vpl, dir, dist, lightsurf_normal, use_normal, standard_scale, sky_scale, hotspot_clamp); + const qvec3f indirect = GetSurfaceLighting(cfg, vpl, vpl_setting, dir, dist, lightsurf_normal, + use_normal, standard_scale, sky_scale, hotspot_clamp); if (!qv::gate(indirect, surflight_gate)) { // Each point contributes very little to the final result rs.pushRay(i, pos, dir, dist, &indirect); } @@ -2038,7 +2056,7 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t total_surflight_rays += rs.numPushedRays(); rs.tracePushedRaysOcclusion(lightsurf->modelinfo, CHANNEL_MASK_DEFAULT); - const int lightmapstyle = vpl.style; + const int lightmapstyle = vpl_setting.style; lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf); bool hit = false; @@ -2050,7 +2068,7 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t const int i = rs.getPushedRayPointIndex(j); qvec3f indirect = rs.getPushedRayColor(j); - Q_assert(!std::isnan(indirect[0])); + //Q_assert(!std::isnan(indirect[0])); // Use dirt scaling on the surface lighting. const vec_t dirtscale = @@ -2070,25 +2088,33 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t } } } +} static void // mxd -LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector *pvs, raystream_occlusion_t &rs, - const std::vector &surface_lights, const vec_t &standard_scale, const vec_t &sky_scale, - const float &hotspot_clamp, const qvec3d &surfpoint, lightgrid_samples_t &result) +LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector *pvs, raystream_occlusion_t &rs, bool bounce, + const vec_t &standard_scale, const vec_t &sky_scale, const float &hotspot_clamp, const qvec3d &surfpoint, + lightgrid_samples_t &result) { const settings::worldspawn_keys &cfg = light_options; const float surflight_gate = 0.01f; - for (const surfacelight_t &vpl : surface_lights) { + for (const auto &surf : LightSurfaces()) { + if (!surf || !surf->vpl) { + continue; + } + + const surfacelight_t &vpl = *surf->vpl; + for (int c = 0; c < vpl.points.size(); c++) { if (light_options.visapprox.value() == visapprox_t::VIS && pvs && VisCullEntity(bsp, *pvs, vpl.leaves[c])) { continue; } - rs.clearPushedRays(); - // 1 ray - { + for (auto &vpl_settings : vpl.styles) { + if (vpl_settings.bounce != bounce) + continue; + qvec3f pos = vpl.points[c]; qvec3f dir = surfpoint - pos; float dist = qv::length(dir); @@ -2100,6 +2126,8 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector *pvs, rays qvec3f indirect{}; + rs.clearPushedRays(); + for (int axis = 0; axis < 3; ++axis) { for (int sign = -1; sign <= +1; sign += 2) { @@ -2108,8 +2136,8 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector *pvs, rays qvec3f cube_normal{}; cube_normal[axis] = sign; - cube_color = GetSurfaceLighting( - cfg, &vpl, dir, dist, cube_normal, true, standard_scale, sky_scale, hotspot_clamp); + cube_color = GetSurfaceLighting(cfg, vpl, vpl_settings, dir, dist, cube_normal, true, + standard_scale, sky_scale, hotspot_clamp); #ifdef LIGHTPOINT_TAKE_MAX if (qv::length2(cube_color) > qv::length2(indirect)) { @@ -2124,7 +2152,6 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector *pvs, rays if (!qv::gate(indirect, surflight_gate)) { // Each point contributes very little to the final result rs.pushRay(0, pos, dir, dist, &indirect); } - } if (!rs.numPushedRays()) continue; @@ -2138,13 +2165,14 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector *pvs, rays qvec3f indirect = rs.getPushedRayColor(j); - Q_assert(!std::isnan(indirect[0])); + //Q_assert(!std::isnan(indirect[0])); - result.add(indirect, vpl.style); + result.add(indirect, vpl_settings.style); } } } } +} static void LightFace_OccludedDebug(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps) { @@ -3333,8 +3361,8 @@ void DirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings:: // mxd. Add surface lights... // FIXME: negative surface lights - LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, GetSurfaceLights(), cfg.surflightscale.value(), - cfg.surflightskyscale.value(), 16.0f); + LightFace_SurfaceLight( + bsp, &lightsurf, lightmaps, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(), 16.0f); } LightFace_LocalMin(bsp, face, &lightsurf, lightmaps); @@ -3373,8 +3401,8 @@ void IndirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings /* add bounce lighting */ // note: scale here is just to keep it close-ish to the old code - LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, BounceLights(), cfg.bouncescale.value() * 0.5, - cfg.bouncescale.value(), 128.0f); + LightFace_SurfaceLight( + bsp, &lightsurf, lightmaps, true, cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(), 128.0f); } } } @@ -3413,9 +3441,10 @@ void PostProcessLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const setti LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, 0); } + if (lightsurf.vpl) { if (auto value = IsSurfaceLitFace(bsp, face)) { auto *entity = std::get<3>(value.value()); - float surface_minlight_scale = entity ? entity->surflight_minlight_scale.value() : 64.f; + float surface_minlight_scale = entity ? entity->surflight_minlight_scale.value() : 1.f; surface_minlight_scale *= lightsurf.surflight_minlight_scale; if (surface_minlight_scale > 0) { @@ -3425,6 +3454,7 @@ void PostProcessLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const setti bsp, face, minlight_color, minlight, &lightsurf, lightmaps, std::get<1>(value.value())); } } + } if (!modelinfo->isWorld()) { LightFace_AutoMin(bsp, face, &lightsurf, lightmaps); @@ -3581,8 +3611,8 @@ lightgrid_samples_t CalcLightgridAtPoint(const mbsp_t *bsp, const qvec3d &world_ // mxd. Add surface lights... // FIXME: negative surface lights - LightPoint_SurfaceLight(bsp, pvs, rs, GetSurfaceLights(), cfg.surflightscale.value(), cfg.surflightskyscale.value(), - 16.0f, world_point, result); + LightPoint_SurfaceLight( + bsp, pvs, rs, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(), 16.0f, world_point, result); #if 0 // FIXME: port to lightgrid @@ -3613,8 +3643,8 @@ lightgrid_samples_t CalcLightgridAtPoint(const mbsp_t *bsp, const qvec3d &world_ /* add bounce lighting */ // note: scale here is just to keep it close-ish to the old code - LightPoint_SurfaceLight(bsp, pvs, rs, BounceLights(), cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(), - 128.0f, world_point, result); + LightPoint_SurfaceLight( + bsp, pvs, rs, true, cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(), 128.0f, world_point, result); LightPoint_ScaleAndClamp(result); diff --git a/light/surflight.cc b/light/surflight.cc index 12bad1f4..2dd72540 100644 --- a/light/surflight.cc +++ b/light/surflight.cc @@ -37,23 +37,13 @@ See file, 'COPYING', for details. #include -static std::mutex surfacelights_lock; -static std::vector surfacelights; -static std::map> surfacelightsByFacenum; -static size_t total_surflight_points = 0; +static std::atomic_size_t total_surflight_points; void ResetSurflight() { - surfacelights = {}; - surfacelightsByFacenum = {}; total_surflight_points = {}; } -std::vector &GetSurfaceLights() -{ - return surfacelights; -} - size_t GetSurflightPoints() { return total_surflight_points; @@ -64,6 +54,14 @@ int LightStyleForTargetname(const settings::worldspawn_keys &cfg, const std::str static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, const mface_t *face, std::optional texture_color, bool is_directional, bool is_sky, int32_t style, int32_t light_value) { + auto &surf_ptr = LightSurfaces()[face - bsp->dfaces.data()]; + + if (!surf_ptr || !Face_IsEmissive(bsp, face)) { + return; + } + + auto &surf = *surf_ptr.get(); + // Create face points... auto poly = Face_Points(bsp, face); const float facearea = qv::PolyArea(poly.begin(), poly.end()); @@ -74,38 +72,6 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys if (facearea < 1) return; - // Create winding... - polylib::winding_t winding = polylib::winding_t::from_winding_points(poly); - auto face_modelinfo = ModelInfoForFace(bsp, face - bsp->dfaces.data()); - - for (auto &pt : winding) { - pt += face_modelinfo->offset; - } - - winding.remove_colinear(); - - // Get face normal and midpoint... - qvec3d facenormal = Face_Normal(bsp, face); - qvec3d facemidpoint = winding.center() + facenormal; // Lift 1 unit - - // Dice winding... - std::vector points; - size_t points_before_culling = 0; - winding.dice(cfg.surflightsubdivision.value(), [&](polylib::winding_t &w) { - ++points_before_culling; - - qvec3f point = w.center() + facenormal; - - // optimization - cull surface lights in the void - // also try to move them if they're slightly inside a wall - auto [fixed_point, success] = FixLightOnFace(bsp, point, false, 0.5f); - if (!success) { - return; - } - - points.push_back(fixed_point); - }); - // Calculate emit color and intensity... if (extended_flags.surflight_color.has_value()) { @@ -137,52 +103,113 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys if (intensity > 1.0f) texture_color.value() *= 1.0f / intensity; - // Sanity checks... - if (points.empty()) - return; + if (!surf.vpl) { + auto &l = surf.vpl = std::make_unique(); - // Add surfacelight... - surfacelight_t l; - l.surfnormal = facenormal; - l.omnidirectional = !is_directional; - l.points = std::move(points); - if (extended_flags.surflight_targetname) { - l.style = LightStyleForTargetname(cfg, extended_flags.surflight_targetname.value()); - } else if (extended_flags.surflight_style) { - l.style = extended_flags.surflight_style.value(); - } else { - l.style = style; + // Create winding... + auto winding = polylib::winding_t::from_winding_points(poly); + auto face_modelinfo = ModelInfoForFace(bsp, face - bsp->dfaces.data()); + + for (auto &pt : winding) { + pt += face_modelinfo->offset; } - l.rescale = extended_flags.surflight_rescale; - l.minlight_scale = extended_flags.surflight_minlight_scale; + + winding.remove_colinear(); + + // Get face normal and midpoint... + l->surfnormal = Face_Normal(bsp, face); + l->pos = winding.center() + l->surfnormal; // Lift 1 unit + + // Dice winding... + l->points_before_culling = 0; + + if (light_options.emissivequality.value() == emissivequality_t::LOW || + light_options.emissivequality.value() == emissivequality_t::MEDIUM) { + l->points = {l->pos}; + l->points_before_culling++; + total_surflight_points++; + + if (light_options.emissivequality.value() == emissivequality_t::MEDIUM) { + + for (auto &pt : winding) { + l->points_before_culling++; + auto point = pt + l->surfnormal; + auto diff = qv::normalize(l->pos - pt); + + point += diff; + + // optimization - cull surface lights in the void + // also try to move them if they're slightly inside a wall + auto [fixed_point, success] = FixLightOnFace(bsp, point, false, 0.5f); + if (!success) { + continue; + } + + l->points.push_back(fixed_point); + total_surflight_points++; + } + } + } else { + winding.dice(cfg.surflightsubdivision.value(), [&](polylib::winding_t &w) { + ++l->points_before_culling; + + qvec3f point = w.center() + l->surfnormal; + + // optimization - cull surface lights in the void + // also try to move them if they're slightly inside a wall + auto [fixed_point, success] = FixLightOnFace(bsp, point, false, 0.5f); + if (!success) { + return; + } + + l->points.push_back(fixed_point); + ++total_surflight_points; + }); + } + + l->minlight_scale = extended_flags.surflight_minlight_scale; // Init bbox... if (light_options.visapprox.value() == visapprox_t::RAYS) { - l.bounds = EstimateVisibleBoundsAtPoint(facemidpoint); + l->bounds = EstimateVisibleBoundsAtPoint(l->pos); } - for (auto &pt : l.points) { + for (auto &pt : l->points) { if (light_options.visapprox.value() == visapprox_t::VIS) { - l.leaves.push_back(Light_PointInLeaf(bsp, pt)); + l->leaves.push_back(Light_PointInLeaf(bsp, pt)); } else if (light_options.visapprox.value() == visapprox_t::RAYS) { - l.bounds += EstimateVisibleBoundsAtPoint(pt); + l->bounds += EstimateVisibleBoundsAtPoint(pt); } } + } - l.pos = facemidpoint; + auto &l = surf.vpl; + + // Sanity checks... + if (l->points.empty()) { + return; + } + + // Add surfacelight... + auto &setting = l->styles.emplace_back(); + setting.omnidirectional = !is_directional; + if (extended_flags.surflight_targetname) { + setting.style = LightStyleForTargetname(cfg, extended_flags.surflight_targetname.value()); + } else if (extended_flags.surflight_style) { + setting.style = extended_flags.surflight_style.value(); + } else { + setting.style = style; + } + if (extended_flags.surflight_rescale) { + setting.rescale = extended_flags.surflight_rescale.value(); + } else { + setting.rescale = is_sky ? false : true; + } // Store surfacelight settings... - l.totalintensity = intensity * facearea; - l.intensity = l.totalintensity / points_before_culling; - l.color = texture_color.value(); - - // Store light... - std::unique_lock lck{surfacelights_lock}; - total_surflight_points += l.points.size(); - surfacelights.push_back(l); - - const int index = static_cast(surfacelights.size()) - 1; - surfacelightsByFacenum[Face_GetNum(bsp, face)].push_back(index); + setting.totalintensity = intensity * facearea; + setting.intensity = setting.totalintensity / l->points_before_culling; + setting.color = texture_color.value(); } std::optional> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face) @@ -251,17 +278,6 @@ static void MakeSurfaceLightsThread(const mbsp_t *bsp, const settings::worldspaw } } -// No surflight_debug (yet?), so unused... -const std::vector &SurfaceLightsForFaceNum(int facenum) -{ - const auto &vec = surfacelightsByFacenum.find(facenum); - if (vec != surfacelightsByFacenum.end()) - return vec->second; - - static std::vector empty; - return empty; -} - void // Quake 2 surface lights MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp) { @@ -270,7 +286,7 @@ MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *b logging::parallel_for( static_cast(0), bsp->dfaces.size(), [&](size_t i) { MakeSurfaceLightsThread(bsp, cfg, i); }); - if (surfacelights.size()) { + /*if (surfacelights.size()) { logging::print("{} surface lights ({} light points) in use.\n", surfacelights.size(), total_surflight_points); -} + }*/ } diff --git a/qbsp/map.cc b/qbsp/map.cc index 1a93778a..d2a3a167 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -678,8 +678,9 @@ static surfflags_t SurfFlagsForEntity( flags.no_minlight = true; if (entity.epairs.get_int("_lightignore") == 1) flags.light_ignore = true; - if (entity.epairs.has("_surflight_rescale") && entity.epairs.get_int("_surflight_rescale") == 0) - flags.surflight_rescale = false; + if (entity.epairs.has("_surflight_rescale")) { + flags.surflight_rescale = entity.epairs.get_int("_surflight_rescale") == 1; + } { qvec3d color; // FIXME: get_color, to match settings diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index ca511a32..91da6ea7 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -381,8 +381,8 @@ static void WriteExtendedTexinfoFlags(void) if (tx.flags.light_ignore) { t["light_ignore"] = tx.flags.light_ignore; } - if (tx.flags.surflight_rescale == false) { - t["surflight_rescale"] = tx.flags.surflight_rescale; + if (tx.flags.surflight_rescale) { + t["surflight_rescale"] = tx.flags.surflight_rescale.value(); } if (tx.flags.surflight_style.has_value()) { t["surflight_style"] = tx.flags.surflight_style.value();