diff --git a/include/light/light.hh b/include/light/light.hh index a50566ac..ea488d57 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -538,6 +538,8 @@ extern std::vector filebase; extern std::vector lit_filebase; extern std::vector lux_filebase; +std::vector> &LightSurfaces(); + extern std::vector extended_texinfo_flags; bool Leaf_HasSky(const mbsp_t *bsp, const mleaf_t *leaf); diff --git a/include/light/ltface.hh b/include/light/ltface.hh index 6faa2d45..b8efcd9e 100644 --- a/include/light/ltface.hh +++ b/include/light/ltface.hh @@ -81,8 +81,13 @@ std::map GetDirectLighting( void SetupDirt(settings::worldspawn_keys &cfg); float DirtAtPoint(const settings::worldspawn_keys &cfg, raystream_intersection_t *rs, const qvec3d &point, const qvec3d &normal, const modelinfo_t *selfshadow); +std::unique_ptr CreateLightmapSurface(const mbsp_t *bsp, const mface_t *face, const facesup_t *facesup, const settings::worldspawn_keys &cfg); bool Face_IsLightmapped(const mbsp_t *bsp, const mface_t *face); -void LightFace(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, const settings::worldspawn_keys &cfg); +void LightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::worldspawn_keys &cfg); +void FinishLightmapSurface( + const mbsp_t *bsp, lightsurf_t *lightsurf); +void SaveLightmapSurface( + const mbsp_t *bsp, mface_t *face, facesup_t *facesup, const lightsurf_t *lightsurf); inline qmat4x4f TexSpaceToWorld(const mbsp_t *bsp, const mface_t *f) { diff --git a/include/light/surflight.hh b/include/light/surflight.hh index 1b4dc54c..2e1ad295 100644 --- a/include/light/surflight.hh +++ b/include/light/surflight.hh @@ -46,6 +46,5 @@ struct surfacelight_t }; const std::vector &SurfaceLights(); -int TotalSurfacelightPoints(); const std::vector &SurfaceLightsForFaceNum(int facenum); void MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp); diff --git a/light/bounce.cc b/light/bounce.cc index 38880f1a..e0972cc3 100644 --- a/light/bounce.cc +++ b/light/bounce.cc @@ -45,9 +45,9 @@ using namespace std; using namespace polylib; -mutex radlights_lock; -static std::vector radlights; -std::map> radlightsByFacenum; +mutex bouncelights_lock; +static std::vector bouncelights; +std::map> bouncelightsByFacenum; class patch_t { @@ -149,22 +149,22 @@ static void AddBounceLight(const qvec3d &pos, const std::map &color l.bounds = EstimateVisibleBoundsAtPoint(pos); } - unique_lock lck{radlights_lock}; - radlights.push_back(l); + unique_lock lck{bouncelights_lock}; + bouncelights.push_back(l); - const int lastBounceLightIndex = static_cast(radlights.size()) - 1; - radlightsByFacenum[Face_GetNum(bsp, face)].push_back(lastBounceLightIndex); + const int lastBounceLightIndex = static_cast(bouncelights.size()) - 1; + bouncelightsByFacenum[Face_GetNum(bsp, face)].push_back(lastBounceLightIndex); } const std::vector &BounceLights() { - return radlights; + return bouncelights; } const std::vector &BounceLightsForFaceNum(int facenum) { - const auto &vec = radlightsByFacenum.find(facenum); - if (vec != radlightsByFacenum.end()) { + const auto &vec = bouncelightsByFacenum.find(facenum); + if (vec != bouncelightsByFacenum.end()) { return vec->second; } @@ -172,12 +172,6 @@ const std::vector &BounceLightsForFaceNum(int facenum) return empty; } -struct make_bounce_lights_args_t -{ - const mbsp_t *bsp; - const settings::worldspawn_keys &cfg; -}; - static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const mbsp_t *bsp, const mface_t &face) { if (!Face_ShouldBounce(bsp, &face)) { @@ -263,5 +257,5 @@ void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp) MakeBounceLightsThread(cfg, bsp, face); }); - logging::print("{} bounce lights created\n", radlights.size()); + logging::print("{} bounce lights created\n", bouncelights.size()); } diff --git a/light/entities.cc b/light/entities.cc index 16a901fa..a1846b09 100644 --- a/light/entities.cc +++ b/light/entities.cc @@ -32,7 +32,7 @@ std::vector> all_lights; std::vector all_suns; std::vector entdicts; -static std::vector radlights; +std::vector radlights; const std::vector> &GetLights() { @@ -978,15 +978,15 @@ inline qvec3d UniformPointOnSphere(vec_t u1, vec_t u2) aabb3d EstimateVisibleBoundsAtPoint(const qvec3d &point) { - const int N = 32; - const int N2 = N * N; + constexpr size_t N = 32; + constexpr size_t N2 = N * N; raystream_intersection_t rs{N2}; aabb3d bounds = point; - for (int x = 0; x < N; x++) { - for (int y = 0; y < N; y++) { + for (size_t x = 0; x < N; x++) { + for (size_t y = 0; y < N; y++) { const vec_t u1 = static_cast(x) / static_cast(N - 1); const vec_t u2 = static_cast(y) / static_cast(N - 1); @@ -1030,10 +1030,6 @@ inline void EstimateLightAABB(const std::unique_ptr &light) void EstimateLightVisibility(void) { - if (options.visapprox.value() != visapprox_t::RAYS) { - return; - } - logging::print("--- EstimateLightVisibility ---\n"); logging::parallel_for_each(all_lights, EstimateLightAABB); @@ -1059,8 +1055,9 @@ void SetupLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp) SetupSuns(cfg); SetupSkyDomes(cfg); FixLightsOnFaces(bsp); - EstimateLightVisibility(); - if (options.visapprox.value() == visapprox_t::VIS) { + if (options.visapprox.value() == visapprox_t::RAYS) { + EstimateLightVisibility(); + } else if (options.visapprox.value() == visapprox_t::VIS) { SetupLightLeafnums(bsp); } diff --git a/light/light.cc b/light/light.cc index a8577747..ec7dda1e 100644 --- a/light/light.cc +++ b/light/light.cc @@ -55,10 +55,16 @@ #include #include -using namespace std; - bool dirt_in_use = false; +// intermediate representation of lightmap surfaces +static std::vector> light_surfaces; + +std::vector> &LightSurfaces() +{ + return light_surfaces; +} + static std::vector faces_sup; // lit2/bspx stuff /// start of lightmap data @@ -302,40 +308,70 @@ const img::texture *Face_Texture(const mbsp_t *bsp, const mface_t *face) return img::find(name); } -static void LightThread(const mbsp_t *bsp, size_t facenum) +static void CreateLightmapSurfaces(mbsp_t *bsp) { -#if defined(HAVE_EMBREE) && defined (__SSE2__) - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); -// _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); -#endif + light_surfaces.resize(bsp->dfaces.size()); + logging::print("--- CreateLightmapSurfaces ---\n"); + logging::parallel_for(static_cast(0), bsp->dfaces.size(), [&bsp](size_t i) { + auto facesup = faces_sup.empty() ? nullptr : &faces_sup[i]; + auto face = &bsp->dfaces[i]; - mface_t *f = BSP_GetFace(const_cast(bsp), facenum); + /* One extra lightmap is allocated to simplify handling overflow */ + if (!options.litonly.value()) { + // if litonly is set we need to preserve the existing lightofs - /* Find the correct model offset */ - const modelinfo_t *face_modelinfo = ModelInfoForFace(bsp, facenum); - if (face_modelinfo == NULL) { - // ericw -- silenced this warning becasue is causes spam when "skip" faces are used - // logging::print("warning: no model has face {}\n", facenum); - return; - } - - if (faces_sup.empty()) { - LightFace(bsp, f, nullptr, options); - } else if (options.novanilla.value()) { - f->lightofs = -1; - f->styles[0] = INVALID_LIGHTSTYLE_OLD; - LightFace(bsp, f, &faces_sup[facenum], options); - } else if (faces_sup[facenum].lmscale == face_modelinfo->lightmapscale) { - LightFace(bsp, f, &faces_sup[facenum], options); - f->lightofs = faces_sup[facenum].lightofs; - for (int i = 0; i < MAXLIGHTMAPS; i++) { - f->styles[i] = faces_sup[facenum].styles[i]; + /* some surfaces don't need lightmaps */ + if (facesup) { + facesup->lightofs = -1; + for (size_t i = 0; i < MAXLIGHTMAPSSUP; i++) { + facesup->styles[i] = INVALID_LIGHTSTYLE; + } + } else { + face->lightofs = -1; + for (size_t i = 0; i < MAXLIGHTMAPS; i++) { + face->styles[i] = INVALID_LIGHTSTYLE_OLD; + } + } } - } else { - LightFace(bsp, f, nullptr, options); - LightFace(bsp, f, &faces_sup[facenum], options); - } + light_surfaces[i] = std::move(CreateLightmapSurface(bsp, face, facesup, options)); + }); +} + +static void SaveLightmapSurfaces(mbsp_t *bsp) +{ + logging::print("--- SaveLightmapSurfaces ---\n"); + logging::parallel_for(static_cast(0), bsp->dfaces.size(), [&bsp](size_t i) { + auto &surf = light_surfaces[i]; + + if (!surf) { + return; + } + + FinishLightmapSurface(bsp, surf.get()); + + auto f = &bsp->dfaces[i]; + const modelinfo_t *face_modelinfo = ModelInfoForFace(bsp, i); + + if (faces_sup.empty()) { + SaveLightmapSurface(bsp, f, nullptr, surf.get()); + } else if (options.novanilla.value()) { + f->lightofs = -1; + f->styles[0] = INVALID_LIGHTSTYLE_OLD; + SaveLightmapSurface(bsp, f, &faces_sup[i], surf.get()); + } else if (faces_sup[i].lmscale == face_modelinfo->lightmapscale) { + SaveLightmapSurface(bsp, f, &faces_sup[i], surf.get()); + f->lightofs = faces_sup[i].lightofs; + for (int i = 0; i < MAXLIGHTMAPS; i++) { + f->styles[i] = faces_sup[i].styles[i]; + } + } else { + SaveLightmapSurface(bsp, f, nullptr, surf.get()); + SaveLightmapSurface(bsp, f, &faces_sup[i], surf.get()); + } + + light_surfaces[i].reset(); + }); } static void FindModelInfo(const mbsp_t *bsp) @@ -429,6 +465,7 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale) mbsp_t &bsp = std::get(bspdata->bsp); + light_surfaces.clear(); filebase.clear(); lit_filebase.clear(); lux_filebase.clear(); @@ -448,8 +485,9 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale) lux_file_p = 0; lux_file_end = (MAX_MAP_LIGHTING * 3); - if (forcedscale) + if (forcedscale) { bspdata->bspx.entries.erase("LMSHIFT"); + } auto lmshift_lump = bspdata->bspx.entries.find("LMSHIFT"); @@ -471,6 +509,9 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale) CalculateVertexNormals(&bsp); + // create lightmap surfaces + CreateLightmapSurfaces(&bsp); + const bool isQuake2map = bsp.loadversion->game->id == GAME_QUAKE_II; // mxd const bool bouncerequired = options.bounce.value() && (options.debugmode == debugmodes::none || options.debugmode == debugmodes::bounce || @@ -484,16 +525,6 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale) } } - if (SurfaceLights().size()) { - logging::print("{} surface lights ({} light points) in use.\n", - SurfaceLights().size(), TotalSurfacelightPoints()); - } - - if (BounceLights().size()) { // mxd. Print some extra stats... - logging::print("{} bounce lights in use.\n", - BounceLights().size()); - } - #if 0 lightbatchthread_info_t info; info.all_batches = MakeLightingBatches(bsp); @@ -503,10 +534,18 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale) #else logging::print("--- LightThread ---\n"); // mxd logging::parallel_for(static_cast(0), bsp.dfaces.size(), [&bsp](size_t i) { - LightThread(&bsp, i); + if (light_surfaces[i]) { +#if defined(HAVE_EMBREE) && defined (__SSE2__) + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); +#endif + + LightFace(&bsp, *light_surfaces[i].get(), options); + } }); #endif + SaveLightmapSurfaces(&bsp); + logging::print("Lighting Completed.\n\n"); // Transfer greyscale lightmap (or color lightmap for Q2/HL) to the bsp and update lightdatasize @@ -712,8 +751,8 @@ static void ExportObj(const fs::path &filename, const mbsp_t *bsp) } // obj -static vector> faceleafs; -static vector leafhassky; +static std::vector> faceleafs; +static std::vector leafhassky; // index some stuff from the bsp static void BuildPvsIndex(const mbsp_t *bsp) diff --git a/light/ltface.cc b/light/ltface.cc index ca52178c..74228244 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -860,19 +860,32 @@ static void CalcPvs(const mbsp_t *bsp, lightsurf_t *lightsurf) } } -static bool Lightsurf_Init( - const modelinfo_t *modelinfo, const mface_t *face, const mbsp_t *bsp, lightsurf_t *lightsurf, facesup_t *facesup) +static std::unique_ptr Lightsurf_Init( + const modelinfo_t *modelinfo, const settings::worldspawn_keys &cfg, const mface_t *face, const mbsp_t *bsp, const facesup_t *facesup) { - /*FIXME: memset can be slow on large datasets*/ - // memset(lightsurf, 0, sizeof(*lightsurf)); + auto spaceToWorld = TexSpaceToWorld(bsp, face); + + /* Check for invalid texture axes */ + if (std::isnan(spaceToWorld.at(0, 0))) { + logging::print("Bad texture axes on face:\n"); + PrintFaceInfo(face, bsp); + return nullptr; + } + + auto lightsurf = std::make_unique(); + lightsurf->cfg = &cfg; lightsurf->modelinfo = modelinfo; lightsurf->bsp = bsp; lightsurf->face = face; + + /* if liquid doesn't have the TEX_SPECIAL flag set, the map was qbsp'ed with + * lit water in mind. In that case receive light from both top and bottom. + * (lit will only be rendered in compatible engines, but degrades gracefully.) + */ + lightsurf->twosided = Face_IsTranslucent(bsp, face); - if (facesup) - lightsurf->lightmapscale = facesup->lmscale; - else - lightsurf->lightmapscale = modelinfo->lightmapscale; + // pick the larger of the two scales + lightsurf->lightmapscale = (facesup && facesup->lmscale > modelinfo->lightmapscale) ? facesup->lmscale : modelinfo->lightmapscale; const surfflags_t &extended_flags = extended_texinfo_flags[face->texinfo]; lightsurf->curved = extended_flags.phong_angle != 0; @@ -934,24 +947,17 @@ static bool Lightsurf_Init( } /* Set up the texorg for coordinate transformation */ - lightsurf->texorg.texSpaceToWorld = TexSpaceToWorld(bsp, face); + lightsurf->texorg.texSpaceToWorld = spaceToWorld; lightsurf->texorg.texinfo = &bsp->texinfo[face->texinfo]; lightsurf->texorg.planedist = plane.dist; - /* Check for invalid texture axes */ - if (std::isnan(lightsurf->texorg.texSpaceToWorld.at(0, 0))) { - logging::print("Bad texture axes on face:\n"); - PrintFaceInfo(face, bsp); - return false; - } - const mtexinfo_t *tex = &bsp->texinfo[face->texinfo]; lightsurf->snormal = qv::normalize(tex->vecs.row(0).xyz()); lightsurf->tnormal = -qv::normalize(tex->vecs.row(1).xyz()); /* Set up the surface points */ - CalcFaceExtents(face, bsp, lightsurf); - CalcPoints(modelinfo, modelinfo->offset, lightsurf, bsp, face); + CalcFaceExtents(face, bsp, lightsurf.get()); + CalcPoints(modelinfo, modelinfo->offset, lightsurf.get(), bsp, face); /* Correct the plane for the model offset (must be done last, calculation of face extents / points needs the uncorrected plane) */ @@ -970,10 +976,10 @@ static bool Lightsurf_Init( /* Setup vis data */ if (options.visapprox.value() == visapprox_t::VIS) { - CalcPvs(bsp, lightsurf); + CalcPvs(bsp, lightsurf.get()); } - return true; + return lightsurf; } static void Lightmap_AllocOrClear(lightmap_t *lightmap, const lightsurf_t *lightsurf) @@ -2691,11 +2697,11 @@ static void LightFace_CalculateDirt(lightsurf_t *lightsurf) // clamps negative values. applies gamma and rangescale. clamps values over 255 // N.B. we want to do this before smoothing / downscaling, so huge values don't mess up the averaging. -static void LightFace_ScaleAndClamp(const lightsurf_t *lightsurf, lightmapdict_t *lightmaps) +inline void LightFace_ScaleAndClamp(lightsurf_t *lightsurf) { const settings::worldspawn_keys &cfg = *lightsurf->cfg; - for (lightmap_t &lightmap : *lightmaps) { + for (lightmap_t &lightmap : lightsurf->lightmapsByStyle) { for (int i = 0; i < lightsurf->points.size(); i++) { qvec3d &color = lightmap.samples[i].color; @@ -2718,6 +2724,13 @@ static void LightFace_ScaleAndClamp(const lightsurf_t *lightsurf, lightmapdict_t } } +void FinishLightmapSurface( + const mbsp_t *bsp, lightsurf_t *lightsurf) +{ + /* Apply gamma, rangescale, and clamp */ + LightFace_ScaleAndClamp(lightsurf); +} + static float Lightmap_AvgBrightness(const lightmap_t *lm, const lightsurf_t *lightsurf) { float avgb = 0; @@ -3105,9 +3118,10 @@ bool Face_IsLightmapped(const mbsp_t *bsp, const mface_t *face) static void WriteSingleLightmap(const mbsp_t *bsp, const mface_t *face, const lightsurf_t *lightsurf, const lightmap_t *lm, const int actual_width, const int actual_height, uint8_t *out, uint8_t *lit, uint8_t *lux); -static void WriteLightmaps( - const mbsp_t *bsp, mface_t *face, facesup_t *facesup, const lightsurf_t *lightsurf, const lightmapdict_t *lightmaps) +void SaveLightmapSurface( + const mbsp_t *bsp, mface_t *face, facesup_t *facesup, const lightsurf_t *lightsurf) { + const lightmapdict_t &lightmaps = lightsurf->lightmapsByStyle; const int actual_width = lightsurf->texsize[0] + 1; const int actual_height = lightsurf->texsize[1] + 1; @@ -3132,7 +3146,7 @@ static void WriteLightmaps( } // see if we have computed lighting for this style - for (const lightmap_t &lm : *lightmaps) { + for (const lightmap_t &lm : lightmaps) { if (lm.style == style) { WriteSingleLightmap(bsp, face, lightsurf, &lm, actual_width, actual_height, out, lit, lux); break; @@ -3157,7 +3171,7 @@ static void WriteLightmaps( // intermediate collection for sorting lightmaps std::vector> sortable; - for (const lightmap_t &lightmap : *lightmaps) { + for (const lightmap_t &lightmap : lightmaps) { // skip un-saved lightmaps if (lightmap.style == INVALID_LIGHTSTYLE) continue; @@ -3347,69 +3361,44 @@ static void WriteSingleLightmap(const mbsp_t *bsp, const mface_t *face, const li } } -/* - * ============ - * LightFace - * ============ - */ -void LightFace(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, const settings::worldspawn_keys &cfg) +std::unique_ptr CreateLightmapSurface(const mbsp_t *bsp, const mface_t *face, const facesup_t *facesup, const settings::worldspawn_keys &cfg) { /* Find the correct model offset */ const modelinfo_t *modelinfo = ModelInfoForFace(bsp, Face_GetNum(bsp, face)); if (modelinfo == nullptr) { - return; - } - - /* One extra lightmap is allocated to simplify handling overflow */ - - if (!options.litonly.value()) { - // if litonly is set we need to preserve the existing lightofs - - /* some surfaces don't need lightmaps */ - if (facesup) { - facesup->lightofs = -1; - for (int i = 0; i < MAXLIGHTMAPSSUP; i++) - facesup->styles[i] = INVALID_LIGHTSTYLE; - } else { - face->lightofs = -1; - for (int i = 0; i < MAXLIGHTMAPS; i++) - face->styles[i] = INVALID_LIGHTSTYLE_OLD; - } + return nullptr; } /* don't bother with degenerate faces */ if (face->numedges < 3) - return; + return nullptr; if (!Face_IsLightmapped(bsp, face)) - return; + return nullptr; const char *texname = Face_TextureName(bsp, face); /* don't save lightmaps for "trigger" texture */ if (!Q_strcasecmp(texname, "trigger")) - return; + return nullptr; /* don't save lightmaps for "skip" texture */ if (!Q_strcasecmp(texname, "skip")) - return; + return nullptr; - /* all good, this face is going to be lightmapped. */ - lightsurf_t lightsurf{}; - lightsurf.cfg = &cfg; + return Lightsurf_Init(modelinfo, cfg, face, bsp, facesup); +} - /* if liquid doesn't have the TEX_SPECIAL flag set, the map was qbsp'ed with - * lit water in mind. In that case receive light from both top and bottom. - * (lit will only be rendered in compatible engines, but degrades gracefully.) - */ - if (Face_IsTranslucent(bsp, face)) { - lightsurf.twosided = true; - } +/* + * ============ + * LightFace + * ============ + */ +void LightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::worldspawn_keys &cfg) +{ + auto face = lightsurf.face; + const modelinfo_t *modelinfo = ModelInfoForFace(bsp, Face_GetNum(bsp, face)); - if (!Lightsurf_Init(modelinfo, face, bsp, &lightsurf, facesup)) { - /* invalid texture axes */ - return; - } lightmapdict_t *lightmaps = &lightsurf.lightmapsByStyle; /* calculate dirt (ambient occlusion) but don't use it yet */ @@ -3450,7 +3439,6 @@ void LightFace(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, const setti } /* minlight - Use Q2 surface light, or the greater of global or model minlight. */ - // FIXME: _surface 2 support const mtexinfo_t *texinfo = Face_Texinfo(bsp, face); // mxd. Surface lights... if (texinfo != nullptr && texinfo->value > 0 && (texinfo->flags.native & Q2_SURF_LIGHT)) { LightFace_Min(bsp, face, Face_LookupTextureColor(bsp, face), texinfo->value * 2.0f, &lightsurf, @@ -3501,9 +3489,4 @@ void LightFace(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, const setti if (options.debugmode == debugmodes::debugneighbours) LightFace_DebugNeighbours(&lightsurf, lightmaps); - - /* Apply gamma, rangescale, and clamp */ - LightFace_ScaleAndClamp(&lightsurf, lightmaps); - - WriteLightmaps(bsp, face, facesup, &lightsurf, lightmaps); } diff --git a/light/surflight.cc b/light/surflight.cc index 33a90bc9..d832c894 100644 --- a/light/surflight.cc +++ b/light/surflight.cc @@ -44,7 +44,7 @@ using namespace polylib; mutex surfacelights_lock; std::vector surfacelights; std::map> surfacelightsByFacenum; -int total_surflight_points = 0; +size_t total_surflight_points = 0; 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) { @@ -175,11 +175,6 @@ const std::vector &SurfaceLights() return surfacelights; } -int TotalSurfacelightPoints() -{ - return total_surflight_points; -} - // No surflight_debug (yet?), so unused... const std::vector &SurfaceLightsForFaceNum(int facenum) { @@ -197,4 +192,9 @@ MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *b logging::print("--- MakeRadiositySurfaceLights ---\n"); logging::parallel_for(static_cast(0), bsp->dfaces.size(), [&](size_t i) { MakeSurfaceLightsThread(bsp, cfg, i); }); + + if (surfacelights.size()) { + logging::print("{} surface lights ({} light points) in use.\n", + surfacelights.size(), total_surflight_points); + } }