From fcf39b2ef893356848d194e6d68cfaf62f5ef4a4 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sun, 18 Jun 2023 13:29:53 -0400 Subject: [PATCH] reduce memory usage by only storing VPLs when we need to, and only once fix visapprox auto not actually being auto --- include/light/bounce.hh | 1 - include/light/light.hh | 5 + include/light/surflight.hh | 41 +++--- light/bounce.cc | 85 ++++++------- light/light.cc | 14 ++- light/ltface.cc | 249 +++++++++++++++++++++---------------- light/surflight.cc | 168 +++++++++++-------------- 7 files changed, 299 insertions(+), 264 deletions(-) diff --git a/include/light/bounce.hh b/include/light/bounce.hh index 448fd877..6832b508 100644 --- a/include/light/bounce.hh +++ b/include/light/bounce.hh @@ -33,5 +33,4 @@ // 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 ad45e7d7..cddfdd6a 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -94,6 +94,8 @@ public: using lightmapdict_t = std::vector; +struct surfacelight_t; + struct lightsurf_t { const settings::worldspawn_keys *cfg; @@ -148,6 +150,9 @@ struct lightsurf_t raystream_intersection_t 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 39165b82..02fa5620 100644 --- a/include/light/surflight.hh +++ b/include/light/surflight.hh @@ -27,33 +27,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 c4f98011..e641e7ae 100644 --- a/light/bounce.cc +++ b/light/bounce.cc @@ -40,13 +40,10 @@ using namespace std; using namespace polylib; -mutex bouncelights_lock; -static std::vector bouncelights; static std::atomic_size_t bouncelightpoints; void ResetBounce() { - bouncelights.clear(); bouncelightpoints = 0; } @@ -89,7 +86,7 @@ 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, +static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, lightsurf_t &surf, qvec3d texture_color, int32_t style, const std::vector &points, const winding_t &winding, const vec_t &area, const qvec3d &facenormal, const qvec3d &facemidpoint) { @@ -104,49 +101,47 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys & return; } - // 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; - - // Init bbox... - if (light_options.visapprox.value() == visapprox_t::RAYS) { - l.bounds = EstimateVisibleBoundsAtPoint(facemidpoint); - } - - for (auto &pt : l.points) { - if (light_options.visapprox.value() == visapprox_t::VIS) { - l.leaves.push_back(Light_PointInLeaf(bsp, pt)); - } else if (light_options.visapprox.value() == visapprox_t::RAYS) { - l.bounds += EstimateVisibleBoundsAtPoint(pt); + // Normalize color... + if (intensity > 1.0) { + texture_color *= 1.0 / intensity; } - } - l.pos = facemidpoint; + // Sanity checks... + Q_assert(!points.empty()); + + // Add surfacelight... + l->surfnormal = facenormal; + l->points = points; + + // Init bbox... + if (light_options.visapprox.value() == visapprox_t::RAYS) { + l->bounds = EstimateVisibleBoundsAtPoint(facemidpoint); + } + + for (auto &pt : l->points) { + if (light_options.visapprox.value() == visapprox_t::VIS) { + l->leaves.push_back(Light_PointInLeaf(bsp, pt)); + } else if (light_options.visapprox.value() == visapprox_t::RAYS) { + l->bounds += EstimateVisibleBoundsAtPoint(pt); + } + } + + l->pos = facemidpoint; + } // Store surfacelight settings... - l.totalintensity = intensity * area; - l.intensity = l.totalintensity / l.points.size(); - l.color = texture_color; - - // Store light... - 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) @@ -229,7 +224,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); + bsp, cfg, surf, style.second, style.first, points, winding, area, facenormal, facemidpoint); } } else { vector points; @@ -238,7 +233,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); + bsp, cfg, surf, style.second, style.first, points, winding, area, facenormal, facemidpoint); } } } @@ -249,5 +244,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 9e37f382..baa3653b 100644 --- a/light/light.cc +++ b/light/light.cc @@ -738,7 +738,13 @@ 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(); }); } @@ -1537,7 +1543,11 @@ int light_main(int argc, const char **argv) // check vis approx type if (light_options.visapprox.value() == visapprox_t::AUTO) { - light_options.visapprox.set_value(visapprox_t::RAYS, settings::source::DEFAULT); + 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); @@ -1581,6 +1591,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 857f4fb7..c7204c87 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -1009,11 +1009,20 @@ 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) @@ -1654,14 +1663,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(lightsurf->points[i]); } - Light_ClampMin(sample, value, color); + hit = Light_ClampMin(sample, value, color) || hit; } - - hit = true; } if (hit) { @@ -1735,11 +1743,11 @@ static void LightFace_LocalMin( cfg, lightsurf->occlusion[i], 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++; } @@ -1882,7 +1890,7 @@ static void LightFace_DebugMottle(const lightsurf_t *lightsurf, lightmapdict_t * } // 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 @@ -1895,25 +1903,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, +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; } @@ -1928,7 +1936,7 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur // Get light contribution result = SurfaceLight_ColorAtDist( - cfg, vpl->omnidirectional ? sky_scale : standard_scale, vpl->intensity, vpl->color, dist, hotspot_clamp); + 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; @@ -1939,7 +1947,7 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur static bool // mxd SurfaceLight_SphereCull( - const surfacelight_t *vpl, const lightsurf_t *lightsurf, const vec_t &bouncelight_gate, const float &hotspot_clamp) + 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)) { @@ -1952,15 +1960,15 @@ SurfaceLight_SphereCull( // Get light contribution const qvec3f color = - SurfaceLight_ColorAtDist(cfg, vpl->omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(), - vpl->totalintensity, vpl->color, dist, hotspot_clamp); + 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, + bool bounce, const vec_t &standard_scale, const vec_t &sky_scale, const float &hotspot_clamp) { const settings::worldspawn_keys &cfg = *lightsurf->cfg; @@ -1971,102 +1979,122 @@ 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; + } - raystream_occlusion_t &rs = lightsurf->occlusion_stream; + auto &vpl = *surf_ptr->vpl.get(); - for (int c = 0; c < vpl.points.size(); c++) { - if (light_options.visapprox.value() == visapprox_t::VIS && - VisCullEntity(bsp, lightsurf->pvs, vpl.leaves[c])) { + for (const auto &vpl_setting : surf_ptr->vpl->styles) { + + if (vpl_setting.bounce != bounce) continue; - } - - rs.clearPushedRays(); - - for (int i = 0; i < lightsurf->points.size(); i++) { - if (lightsurf->occluded[i]) - continue; - - const qvec3d &lightsurf_pos = lightsurf->points[i]; - const qvec3d &lightsurf_normal = lightsurf->normals[i]; - - qvec3f pos = vpl.points[c]; - qvec3f dir = lightsurf_pos - pos; - float dist = qv::length(dir); - bool use_normal = true; - - if (dist == 0.0f) { - dir = lightsurf_normal; - use_normal = false; - } else { - dir /= dist; - } - - 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); - } - } - - if (!rs.numPushedRays()) + else if (SurfaceLight_SphereCull(&vpl, lightsurf, vpl_setting, surflight_gate, hotspot_clamp)) continue; - total_surflight_rays += rs.numPushedRays(); - rs.tracePushedRaysOcclusion(lightsurf->modelinfo, CHANNEL_MASK_DEFAULT); + raystream_occlusion_t &rs = lightsurf->occlusion_stream; - const int lightmapstyle = vpl.style; - lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf); + for (int c = 0; c < vpl.points.size(); c++) { + if (light_options.visapprox.value() == visapprox_t::VIS && + VisCullEntity(bsp, lightsurf->pvs, vpl.leaves[c])) { + continue; + } - bool hit = false; - const int numrays = rs.numPushedRays(); - for (int j = 0; j < numrays; j++) { - if (rs.getPushedRayOccluded(j)) + rs.clearPushedRays(); + + for (int i = 0; i < lightsurf->points.size(); i++) { + if (lightsurf->occluded[i]) + continue; + + const qvec3d &lightsurf_pos = lightsurf->points[i]; + const qvec3d &lightsurf_normal = lightsurf->normals[i]; + + qvec3f pos = vpl.points[c]; + qvec3f dir = lightsurf_pos - pos; + float dist = qv::length(dir); + bool use_normal = true; + + if (dist == 0.0f) { + dir = lightsurf_normal; + use_normal = false; + } else { + dir /= dist; + } + + 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); + } + } + + if (!rs.numPushedRays()) continue; - const int i = rs.getPushedRayPointIndex(j); - qvec3f indirect = rs.getPushedRayColor(j); + total_surflight_rays += rs.numPushedRays(); + rs.tracePushedRaysOcclusion(lightsurf->modelinfo, CHANNEL_MASK_DEFAULT); - Q_assert(!std::isnan(indirect[0])); + const int lightmapstyle = vpl_setting.style; + lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf); - // Use dirt scaling on the surface lighting. - const vec_t dirtscale = Dirt_GetScaleFactor(cfg, lightsurf->occlusion[i], nullptr, 0.0, lightsurf); - indirect *= dirtscale; + bool hit = false; + const int numrays = rs.numPushedRays(); + for (int j = 0; j < numrays; j++) { + if (rs.getPushedRayOccluded(j)) + continue; - lightsample_t &sample = lightmap->samples[i]; - sample.color += indirect; + const int i = rs.getPushedRayPointIndex(j); + qvec3f indirect = rs.getPushedRayColor(j); - hit = true; - ++total_surflight_ray_hits; + Q_assert(!std::isnan(indirect[0])); + + // Use dirt scaling on the surface lighting. + const vec_t dirtscale = Dirt_GetScaleFactor(cfg, lightsurf->occlusion[i], nullptr, 0.0, lightsurf); + indirect *= dirtscale; + + lightsample_t &sample = lightmap->samples[i]; + sample.color += indirect; + + hit = true; + ++total_surflight_ray_hits; + } + + // If surface light contributed anything, save. + if (hit) + Lightmap_Save(lightmaps, lightsurf, lightmap, lightmapstyle); } - - // If surface light contributed anything, save. - if (hit) - Lightmap_Save(lightmaps, lightsurf, lightmap, lightmapstyle); } } } 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, + 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); @@ -2078,6 +2106,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) { @@ -2087,7 +2117,7 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector *pvs, rays cube_normal[axis] = sign; cube_color = GetSurfaceLighting( - cfg, &vpl, dir, dist, cube_normal, true, standard_scale, sky_scale, hotspot_clamp); + 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)) { @@ -2102,23 +2132,23 @@ 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; - - rs.tracePushedRaysOcclusion(nullptr, CHANNEL_MASK_DEFAULT); - - const int numrays = rs.numPushedRays(); - for (int j = 0; j < numrays; j++) { - if (rs.getPushedRayOccluded(j)) + if (!rs.numPushedRays()) continue; - qvec3f indirect = rs.getPushedRayColor(j); + rs.tracePushedRaysOcclusion(nullptr, CHANNEL_MASK_DEFAULT); - Q_assert(!std::isnan(indirect[0])); + const int numrays = rs.numPushedRays(); + for (int j = 0; j < numrays; j++) { + if (rs.getPushedRayOccluded(j)) + continue; - result.add(indirect, vpl.style); + qvec3f indirect = rs.getPushedRayColor(j); + + Q_assert(!std::isnan(indirect[0])); + + result.add(indirect, vpl_settings.style); + } } } } @@ -2807,10 +2837,11 @@ bool Face_IsLightmapped(const mbsp_t *bsp, const mface_t *face) // Very specific hack: the only reason to lightmap sky faces in Q2 is to light mdl's floating over sky. // If lightgrid is in use, this reason is no longer relevant, so skip lightmapping. - if (light_options.lightgrid.value() && bsp->loadversion->game->id == GAME_QUAKE_II && + // TEMP DISABLED + /*if (light_options.lightgrid.value() && bsp->loadversion->game->id == GAME_QUAKE_II && (texinfo->flags.native & Q2_SURF_SKY)) { return false; - } + }*/ return bsp->loadversion->game->surf_is_lightmapped(texinfo->flags); } @@ -3308,7 +3339,7 @@ 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(), + LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(), 16.0f); } @@ -3348,7 +3379,7 @@ 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, + LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, true, cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(), 128.0f); } } @@ -3388,15 +3419,17 @@ void PostProcessLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const setti LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, 0); } - 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; - surface_minlight_scale *= lightsurf.surflight_minlight_scale; + 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; + surface_minlight_scale *= lightsurf.surflight_minlight_scale; - if (surface_minlight_scale > 0) { - minlight = std::get<0>(value.value()) * surface_minlight_scale; - minlight_color = std::get<2>(value.value()); - LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, std::get<1>(value.value())); + if (surface_minlight_scale > 0) { + minlight = std::get<0>(value.value()) * surface_minlight_scale; + minlight_color = std::get<2>(value.value()); + LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, std::get<1>(value.value())); + } } } @@ -3555,7 +3588,7 @@ 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(), + LightPoint_SurfaceLight(bsp, pvs, rs, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(), 16.0f, world_point, result); #if 0 @@ -3587,7 +3620,7 @@ 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(), + 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 49856077..6c8f4cf5 100644 --- a/light/surflight.cc +++ b/light/surflight.cc @@ -38,22 +38,13 @@ using namespace std; using namespace polylib; static 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; @@ -64,6 +55,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) { + 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 +73,6 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys if (facearea < 1) return; - // Create winding... - winding_t winding = 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... - vector points; - size_t points_before_culling = 0; - winding.dice(cfg.surflightsubdivision.value(), [&](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 +104,80 @@ 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; - } - l.rescale = extended_flags.surflight_rescale; - l.minlight_scale = extended_flags.surflight_minlight_scale; + // Create winding... + winding_t winding = winding_t::from_winding_points(poly); + auto face_modelinfo = ModelInfoForFace(bsp, face - bsp->dfaces.data()); - // Init bbox... - if (light_options.visapprox.value() == visapprox_t::RAYS) { - l.bounds = EstimateVisibleBoundsAtPoint(facemidpoint); - } + for (auto &pt : winding) { + pt += face_modelinfo->offset; + } - for (auto &pt : l.points) { - if (light_options.visapprox.value() == visapprox_t::VIS) { - l.leaves.push_back(Light_PointInLeaf(bsp, pt)); - } else if (light_options.visapprox.value() == visapprox_t::RAYS) { - l.bounds += EstimateVisibleBoundsAtPoint(pt); + 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; + + winding.dice(cfg.surflightsubdivision.value(), [&](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); + }); + + l->minlight_scale = extended_flags.surflight_minlight_scale; + + // Init bbox... + if (light_options.visapprox.value() == visapprox_t::RAYS) { + l->bounds = EstimateVisibleBoundsAtPoint(l->pos); + } + + for (auto &pt : l->points) { + if (light_options.visapprox.value() == visapprox_t::VIS) { + l->leaves.push_back(Light_PointInLeaf(bsp, pt)); + } else if (light_options.visapprox.value() == visapprox_t::RAYS) { + 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; + } + setting.rescale = extended_flags.surflight_rescale; // Store surfacelight settings... - l.totalintensity = intensity * facearea; - l.intensity = l.totalintensity / points_before_culling; - l.color = texture_color.value(); - - // Store light... - 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 +246,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 +254,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); - } + }*/ }