diff --git a/include/light/bounce.hh b/include/light/bounce.hh index deba5c9d..268e12d0 100644 --- a/include/light/bounce.hh +++ b/include/light/bounce.hh @@ -29,4 +29,5 @@ 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 f5f13905..8a9735b8 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -143,9 +143,6 @@ 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 d104ac5f..a0feac75 100644 --- a/include/light/surflight.hh +++ b/include/light/surflight.hh @@ -39,40 +39,33 @@ struct surfacelight_t { qvec3d pos; qvec3f surfnormal; - size_t points_before_culling; - - // Estimated visible AABB culling - aabb3d bounds; - - std::optional minlight_scale; - + /** + * 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... - 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 - }; + float intensity; // Surface light strength for each point + float totalintensity; // Total surface light strength + qvec3d color; // Surface color - // Light data per style - std::vector styles; -}; + // Estimated visible AABB culling + aabb3d bounds; + + int32_t style; + + // rescale faces to account for perpendicular lights + bool rescale; + std::optional minlight_scale; + }; 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 b02b9956..ff0548a9 100644 --- a/light/bounce.cc +++ b/light/bounce.cc @@ -39,10 +39,13 @@ #include #include +std::mutex bouncelights_lock; +static std::vector bouncelights; static std::atomic_size_t bouncelightpoints; void ResetBounce() { + bouncelights.clear(); bouncelightpoints = 0; } @@ -85,11 +88,11 @@ 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, lightsurf_t &surf, +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, const vec_t &area, const qvec3d &facenormal, const qvec3d &facemidpoint) { - if (!Face_IsEmissive(bsp, surf.face)) { + if (!Face_IsEmissive(bsp, face)) { return; } @@ -104,9 +107,6 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys & return; } - if (!surf.vpl) { - auto &l = surf.vpl = std::make_unique(); - // Normalize color... if (intensity > 1.0) { texture_color *= 1.0 / intensity; @@ -116,36 +116,41 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys & Q_assert(!points.empty()); // Add surfacelight... - l->surfnormal = facenormal; - l->points = points; + surfacelight_t l; + l.surfnormal = facenormal; + l.omnidirectional = false; + l.points = points; + l.style = style; // 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... - { - 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; + 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; } -} static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const mbsp_t *bsp, const mface_t &face) { @@ -240,7 +245,8 @@ static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const m } for (auto &style : emitcolors) { - MakeBounceLight(bsp, cfg, surf, style.second, style.first, points, winding, area, facenormal, facemidpoint); + MakeBounceLight( + bsp, cfg, &face, style.second, style.first, points, winding, area, facenormal, facemidpoint); } } @@ -250,5 +256,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 dcec2946..ba7980e7 100644 --- a/light/light.cc +++ b/light/light.cc @@ -745,13 +745,9 @@ 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); } - }); -} -void ClearLightmapSurfaces(mbsp_t *bsp) -{ - logging::funcheader(); - logging::parallel_for(static_cast(0), bsp->dfaces.size(), [&bsp](size_t i) { light_surfaces[i].reset(); }); + light_surfaces[i].reset(); + }); } static void FindModelInfo(const mbsp_t *bsp) @@ -1548,12 +1544,8 @@ int light_main(int argc, const char **argv) // check vis approx type if (light_options.visapprox.value() == visapprox_t::AUTO) { - if (!bsp.dvis.bits.empty()) { - light_options.visapprox.set_value(visapprox_t::VIS, settings::source::DEFAULT); - } else { light_options.visapprox.set_value(visapprox_t::RAYS, settings::source::DEFAULT); } - } img::load_textures(&bsp, light_options); @@ -1596,8 +1588,6 @@ 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 e7d5fde1..e302a6e6 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include // for facesup_t #include @@ -1012,22 +1013,13 @@ constexpr vec_t SQR(vec_t x) } // CHECK: naming? why clamp*min*? -constexpr bool Light_ClampMin(lightsample_t &sample, const vec_t light, const qvec3d &color) +constexpr void Light_ClampMin(lightsample_t &sample, const vec_t light, const qvec3d &color) { - bool changed = false; - for (int i = 0; i < 3; i++) { - float c = (float)(color[i] * (light / 255.0f)); - - if (c > sample.color[i]) { - sample.color[i] = c; - changed = true; + sample.color[i] = std::max(sample.color[i], (float)(color[i] * (light / 255.0f))); } } - return changed; -} - constexpr vec_t fraction(const vec_t &min, const vec_t &val, const vec_t &max) { if (val >= max) @@ -1671,13 +1663,14 @@ 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); } - hit = Light_ClampMin(sample, value, color) || hit; + Light_ClampMin(sample, value, color); } + + hit = true; } if (hit) { @@ -1753,11 +1746,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 { - hit = Light_ClampMin(sample, value, entity->color.value()) || hit; + Light_ClampMin(sample, value, entity->color.value()); } + hit = true; total_light_ray_hits++; } @@ -1900,7 +1893,7 @@ static void LightFace_DebugMottle(const mbsp_t *bsp, const lightsurf_t *lightsur } // mxd. Surface light falloff. Returns color in [0,255] -constexpr qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg, const float &surf_scale, +inline 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 @@ -1913,25 +1906,25 @@ constexpr qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg, // dir: vpl -> sample point direction // mxd. returns color in [0,255] -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) +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) { 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_settings.omnidirectional) { + if (!vpl->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_settings.rescale) { + if (vpl->rescale) { dp1 = 0.5f + dp1 * 0.5f; dp2 = 0.5f + dp2 * 0.5f; } @@ -1945,8 +1938,8 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur dotProductFactor = std::max(0.0f, dotProductFactor); // Get light contribution - result = SurfaceLight_ColorAtDist(cfg, vpl_settings.omnidirectional ? sky_scale : standard_scale, - vpl_settings.intensity, vpl_settings.color, dist, hotspot_clamp); + result = SurfaceLight_ColorAtDist( + cfg, vpl->omnidirectional ? sky_scale : standard_scale, vpl->intensity, vpl->color, dist, hotspot_clamp); // Apply angle scale const qvec3f resultscaled = result * dotProductFactor; @@ -1956,8 +1949,8 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur } static bool // mxd -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) +SurfaceLight_SphereCull( + const surfacelight_t *vpl, const lightsurf_t *lightsurf, 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)) { @@ -1969,16 +1962,17 @@ SurfaceLight_SphereCull(const surfacelight_t *vpl, const lightsurf_t *lightsurf, const float dist = qv::length(dir) + lightsurf->extents.radius; // Get light contribution - const qvec3f color = SurfaceLight_ColorAtDist(cfg, - vpl_settings.omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(), - vpl_settings.totalintensity, vpl_settings.color, dist, hotspot_clamp); + const qvec3f color = + SurfaceLight_ColorAtDist(cfg, vpl->omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(), + vpl->totalintensity, vpl->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, bool bounce, - 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, + const std::vector &surface_lights, 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; @@ -1988,21 +1982,9 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t return; } - for (const auto &surf_ptr : LightSurfaces()) { - - if (!surf_ptr || !surf_ptr->vpl) { - // didn't emit anthing + for (const surfacelight_t &vpl : surface_lights) { + if (SurfaceLight_SphereCull(&vpl, lightsurf, surflight_gate, hotspot_clamp)) 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; @@ -2035,8 +2017,8 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t dir /= dist; } - const qvec3f indirect = GetSurfaceLighting(cfg, vpl, vpl_setting, dir, dist, lightsurf_normal, - use_normal, standard_scale, sky_scale, hotspot_clamp); + const qvec3f indirect = GetSurfaceLighting( + cfg, &vpl, 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); } @@ -2048,7 +2030,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_setting.style; + const int lightmapstyle = vpl.style; lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf); bool hit = false; @@ -2080,33 +2062,25 @@ 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, bool bounce, - 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, + 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) { const settings::worldspawn_keys &cfg = light_options; const float surflight_gate = 0.01f; - for (const auto &surf : LightSurfaces()) { - if (!surf || !surf->vpl) { - continue; - } - - const surfacelight_t &vpl = *surf->vpl; - + for (const surfacelight_t &vpl : surface_lights) { 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; } - // 1 ray - for (auto &vpl_settings : vpl.styles) { - if (vpl_settings.bounce != bounce) - continue; + rs.clearPushedRays(); + // 1 ray + { qvec3f pos = vpl.points[c]; qvec3f dir = surfpoint - pos; float dist = qv::length(dir); @@ -2118,8 +2092,6 @@ 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) { @@ -2128,8 +2100,8 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector *pvs, rays qvec3f cube_normal{}; cube_normal[axis] = sign; - cube_color = GetSurfaceLighting(cfg, vpl, vpl_settings, dir, dist, cube_normal, true, - standard_scale, sky_scale, hotspot_clamp); + cube_color = GetSurfaceLighting( + cfg, &vpl, dir, dist, cube_normal, true, standard_scale, sky_scale, hotspot_clamp); #ifdef LIGHTPOINT_TAKE_MAX if (qv::length2(cube_color) > qv::length2(indirect)) { @@ -2144,6 +2116,7 @@ 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; @@ -2159,12 +2132,11 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector *pvs, rays Q_assert(!std::isnan(indirect[0])); - result.add(indirect, vpl_settings.style); + result.add(indirect, vpl.style); } } } } -} static void LightFace_OccludedDebug(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps) { @@ -3353,8 +3325,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, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(), 16.0f); + LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, GetSurfaceLights(), cfg.surflightscale.value(), + cfg.surflightskyscale.value(), 16.0f); } LightFace_LocalMin(bsp, face, &lightsurf, lightmaps); @@ -3393,8 +3365,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, true, cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(), 128.0f); + LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, BounceLights(), cfg.bouncescale.value() * 0.5, + cfg.bouncescale.value(), 128.0f); } } } @@ -3433,10 +3405,9 @@ 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() : 1.f; + float surface_minlight_scale = entity ? entity->surflight_minlight_scale.value() : 64.f; surface_minlight_scale *= lightsurf.surflight_minlight_scale; if (surface_minlight_scale > 0) { @@ -3446,7 +3417,6 @@ 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); @@ -3603,8 +3573,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, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(), 16.0f, world_point, result); + LightPoint_SurfaceLight(bsp, pvs, rs, GetSurfaceLights(), cfg.surflightscale.value(), cfg.surflightskyscale.value(), + 16.0f, world_point, result); #if 0 // FIXME: port to lightgrid @@ -3635,8 +3605,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, true, cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(), 128.0f, world_point, result); + LightPoint_SurfaceLight(bsp, pvs, rs, BounceLights(), 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 d20274f6..12bad1f4 100644 --- a/light/surflight.cc +++ b/light/surflight.cc @@ -37,13 +37,23 @@ See file, 'COPYING', for details. #include -static std::atomic_size_t total_surflight_points; +static std::mutex surfacelights_lock; +static std::vector surfacelights; +static std::map> surfacelightsByFacenum; +static size_t total_surflight_points = 0; void ResetSurflight() { + surfacelights = {}; + surfacelightsByFacenum = {}; total_surflight_points = {}; } +std::vector &GetSurfaceLights() +{ + return surfacelights; +} + size_t GetSurflightPoints() { return total_surflight_points; @@ -54,14 +64,6 @@ 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()); @@ -72,6 +74,38 @@ 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()) { @@ -103,109 +137,52 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys if (intensity > 1.0f) texture_color.value() *= 1.0f / intensity; - if (!surf.vpl) { - auto &l = surf.vpl = std::make_unique(); + // Sanity checks... + if (points.empty()) + return; - // 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; + // 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; } - - 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; + l.rescale = extended_flags.surflight_rescale; + l.minlight_scale = extended_flags.surflight_minlight_scale; // Init bbox... if (light_options.visapprox.value() == visapprox_t::RAYS) { - l->bounds = EstimateVisibleBoundsAtPoint(l->pos); + 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); } } - } - 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; - } - setting.rescale = extended_flags.surflight_rescale; + l.pos = facemidpoint; // Store surfacelight settings... - setting.totalintensity = intensity * facearea; - setting.intensity = setting.totalintensity / l->points_before_culling; - setting.color = texture_color.value(); + 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); } std::optional> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face) @@ -274,6 +251,17 @@ 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) { @@ -282,7 +270,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); - }*/ +} }