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();