fix crash in light from bounce lighting storage

move bounce lights to a forwardly linked list
fix minlight affecting style 0 for switchables
This commit is contained in:
Jonathan 2022-07-29 00:41:24 -04:00
parent 7810875860
commit 3ee28fc416
6 changed files with 54 additions and 41 deletions

View File

@ -27,6 +27,7 @@
#include <map> #include <map>
#include <common/qvec.hh> #include <common/qvec.hh>
#include <forward_list>
struct bouncelight_t struct bouncelight_t
{ {
@ -47,7 +48,7 @@ struct bouncelight_t
// public functions // public functions
const std::vector<bouncelight_t> &BounceLights(); const std::forward_list<bouncelight_t> &BounceLights();
const std::vector<int> &BounceLightsForFaceNum(int facenum); const std::vector<std::reference_wrapper<bouncelight_t>> &BounceLightsForFaceNum(int facenum);
void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp); void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp);
qvec3b Face_LookupTextureColor(const mbsp_t *bsp, const mface_t *face); // mxd qvec3b Face_LookupTextureColor(const mbsp_t *bsp, const mface_t *face); // mxd

View File

@ -21,6 +21,7 @@ See file, 'COPYING', for details.
#pragma once #pragma once
#include <vector> #include <vector>
#include <tuple>
struct surfacelight_t struct surfacelight_t
{ {
@ -46,6 +47,6 @@ struct surfacelight_t
}; };
std::vector<surfacelight_t> &GetSurfaceLights(); std::vector<surfacelight_t> &GetSurfaceLights();
std::optional<int32_t> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face); std::optional<std::tuple<int32_t, int32_t>> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face);
const std::vector<int> &SurfaceLightsForFaceNum(int facenum); const std::vector<int> &SurfaceLightsForFaceNum(int facenum);
void MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp); void MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp);

View File

@ -47,8 +47,9 @@ using namespace std;
using namespace polylib; using namespace polylib;
mutex bouncelights_lock; mutex bouncelights_lock;
static std::vector<bouncelight_t> bouncelights; static std::forward_list<bouncelight_t> bouncelights;
std::unordered_map<int, std::vector<int>> bouncelightsByFacenum; static size_t lastBounceLightIndex;
static std::unordered_map<size_t, std::vector<std::reference_wrapper<bouncelight_t>>> bouncelightsByFacenum;
static bool Face_ShouldBounce(const mbsp_t *bsp, const mface_t *face) static bool Face_ShouldBounce(const mbsp_t *bsp, const mface_t *face)
{ {
@ -94,15 +95,14 @@ qvec3b Face_LookupTextureColor(const mbsp_t *bsp, const mface_t *face)
inline bouncelight_t &CreateBounceLight(const mface_t *face, const mbsp_t *bsp) inline bouncelight_t &CreateBounceLight(const mface_t *face, const mbsp_t *bsp)
{ {
unique_lock<mutex> lck{bouncelights_lock}; unique_lock<mutex> lck{bouncelights_lock};
bouncelight_t &l = bouncelights.emplace_back(); bouncelight_t &l = bouncelights.emplace_front();
const int lastBounceLightIndex = static_cast<int>(bouncelights.size()) - 1; bouncelightsByFacenum[Face_GetNum(bsp, face)].push_back(l);
bouncelightsByFacenum[Face_GetNum(bsp, face)].push_back(lastBounceLightIndex);
return l; return l;
} }
static void AddBounceLight(const qvec3d &pos, const std::unordered_map<int, qvec3d> &colorByStyle, static void AddBounceLight(const qvec3d &pos, std::unordered_map<int, qvec3d> &&colorByStyle,
const qvec3d &surfnormal, vec_t area, const mface_t *face, const mbsp_t *bsp) const qvec3d &surfnormal, vec_t area, const mface_t *face, const mbsp_t *bsp)
{ {
for (const auto &styleColor : colorByStyle) { for (const auto &styleColor : colorByStyle) {
@ -118,15 +118,11 @@ static void AddBounceLight(const qvec3d &pos, const std::unordered_map<int, qvec
l.pos = pos; l.pos = pos;
l.colorByStyle = colorByStyle; l.colorByStyle = colorByStyle;
qvec3f componentwiseMaxColor{}; for (const auto &styleColor : l.colorByStyle) {
for (const auto &styleColor : colorByStyle) {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (styleColor.second[i] > componentwiseMaxColor[i]) { l.componentwiseMaxColor[i] = max(l.componentwiseMaxColor[i], styleColor.second[i]);
componentwiseMaxColor[i] = styleColor.second[i];
} }
} }
}
l.componentwiseMaxColor = componentwiseMaxColor;
l.surfnormal = surfnormal; l.surfnormal = surfnormal;
l.area = area; l.area = area;
@ -137,19 +133,19 @@ static void AddBounceLight(const qvec3d &pos, const std::unordered_map<int, qvec
} }
} }
const std::vector<bouncelight_t> &BounceLights() const std::forward_list<bouncelight_t> &BounceLights()
{ {
return bouncelights; return bouncelights;
} }
const std::vector<int> &BounceLightsForFaceNum(int facenum) const std::vector<std::reference_wrapper<bouncelight_t>> &BounceLightsForFaceNum(int facenum)
{ {
const auto &vec = bouncelightsByFacenum.find(facenum); const auto &vec = bouncelightsByFacenum.find(facenum);
if (vec != bouncelightsByFacenum.end()) { if (vec != bouncelightsByFacenum.end()) {
return vec->second; return vec->second;
} }
static std::vector<int> empty; static std::vector<std::reference_wrapper<bouncelight_t>> empty;
return empty; return empty;
} }
@ -215,7 +211,7 @@ static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const m
emitcolors[styleColor.first] = styleColor.second * blendedcolor; emitcolors[styleColor.first] = styleColor.second * blendedcolor;
} }
AddBounceLight(facemidpoint, emitcolors, faceplane.normal, area, &face, bsp); AddBounceLight(facemidpoint, std::move(emitcolors), faceplane.normal, area, &face, bsp);
} }
void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp) void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp)
@ -224,5 +220,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::parallel_for_each(bsp->dfaces, [&](const mface_t &face) { MakeBounceLightsThread(cfg, bsp, face); });
logging::print("{} bounce lights created\n", bouncelights.size()); logging::print("{} bounce lights created\n", lastBounceLightIndex);
} }

View File

@ -1389,7 +1389,7 @@ static void LightFace_Sky(const sun_t *sun, lightsurf_t *lightsurf, lightmapdict
* ============ * ============
*/ */
static void LightFace_Min(const mbsp_t *bsp, const mface_t *face, const qvec3d &color, vec_t light, static void LightFace_Min(const mbsp_t *bsp, const mface_t *face, const qvec3d &color, vec_t light,
lightsurf_t *lightsurf, lightmapdict_t *lightmaps) lightsurf_t *lightsurf, lightmapdict_t *lightmaps, int32_t style)
{ {
const settings::worldspawn_keys &cfg = *lightsurf->cfg; const settings::worldspawn_keys &cfg = *lightsurf->cfg;
const modelinfo_t *modelinfo = lightsurf->modelinfo; const modelinfo_t *modelinfo = lightsurf->modelinfo;
@ -1399,8 +1399,8 @@ static void LightFace_Min(const mbsp_t *bsp, const mface_t *face, const qvec3d &
return; /* this face is excluded from minlight */ return; /* this face is excluded from minlight */
} }
/* Find a style 0 lightmap */ /* Find the lightmap */
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, 0, lightsurf); lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, style, lightsurf);
bool hit = false; bool hit = false;
for (int i = 0; i < lightsurf->points.size(); i++) { for (int i = 0; i < lightsurf->points.size(); i++) {
@ -1423,7 +1423,19 @@ static void LightFace_Min(const mbsp_t *bsp, const mface_t *face, const qvec3d &
} }
if (hit) { if (hit) {
Lightmap_Save(lightmaps, lightsurf, lightmap, 0); Lightmap_Save(lightmaps, lightsurf, lightmap, style);
}
}
static void LightFace_LocalMin(const mbsp_t *bsp, const mface_t *face,
lightsurf_t *lightsurf, lightmapdict_t *lightmaps)
{
const settings::worldspawn_keys &cfg = *lightsurf->cfg;
const modelinfo_t *modelinfo = lightsurf->modelinfo;
const surfflags_t &extended_flags = extended_texinfo_flags[face->texinfo];
if (extended_flags.no_minlight) {
return; /* this face is excluded from minlight */
} }
// FIXME: Refactor this? // FIXME: Refactor this?
@ -1446,9 +1458,9 @@ static void LightFace_Min(const mbsp_t *bsp, const mface_t *face, const qvec3d &
raystream_occlusion_t &rs = lightsurf->occlusion_stream; raystream_occlusion_t &rs = lightsurf->occlusion_stream;
rs.clearPushedRays(); rs.clearPushedRays();
lightmap = Lightmap_ForStyle(lightmaps, entity->style.value(), lightsurf); lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, entity->style.value(), lightsurf);
hit = false; bool hit = false;
for (int i = 0; i < lightsurf->points.size(); i++) { for (int i = 0; i < lightsurf->points.size(); i++) {
if (lightsurf->occluded[i]) if (lightsurf->occluded[i])
continue; continue;
@ -1547,16 +1559,15 @@ static void LightFace_BounceLightsDebug(const lightsurf_t *lightsurf, lightmapdi
// reset all lightmaps to black (lazily) // reset all lightmaps to black (lazily)
Lightmap_ClearAll(lightmaps); Lightmap_ClearAll(lightmaps);
const std::vector<int> &vpls = BounceLightsForFaceNum(Face_GetNum(lightsurf->bsp, lightsurf->face)); const std::vector<std::reference_wrapper<bouncelight_t>> &vpls = BounceLightsForFaceNum(Face_GetNum(lightsurf->bsp, lightsurf->face));
const std::vector<bouncelight_t> &all_vpls = BounceLights();
/* Overwrite each point with the emitted color... */ /* Overwrite each point with the emitted color... */
for (int i = 0; i < lightsurf->points.size(); i++) { for (int i = 0; i < lightsurf->points.size(); i++) {
if (lightsurf->occluded[i]) if (lightsurf->occluded[i])
continue; continue;
for (const auto &vplnum : vpls) { for (const auto &vpl_ref : vpls) {
const bouncelight_t &vpl = all_vpls[vplnum]; auto &vpl = vpl_ref.get();
// check for point in polygon (note: could be on the edge of more than one) // check for point in polygon (note: could be on the edge of more than one)
if (!GLM_EdgePlanes_PointInside(vpl.poly_edgeplanes, lightsurf->points[i])) if (!GLM_EdgePlanes_PointInside(vpl.poly_edgeplanes, lightsurf->points[i]))
@ -2966,7 +2977,7 @@ void DirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::
float minlight = 0; float minlight = 0;
qvec3d minlight_color; qvec3d minlight_color;
/* minlight - use the greater of global or model minlight, or Q2 surface emission */ // first, check for global minlight; this only affects style 0
if (lightsurf.minlight > cfg.minlight.value()) { if (lightsurf.minlight > cfg.minlight.value()) {
minlight = lightsurf.minlight; minlight = lightsurf.minlight;
minlight_color = lightsurf.minlight_color; minlight_color = lightsurf.minlight_color;
@ -2975,17 +2986,18 @@ void DirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::
minlight_color = cfg.minlight_color.value(); minlight_color = cfg.minlight_color.value();
} }
if (!minlight) { if (minlight) {
if (auto value = IsSurfaceLitFace(bsp, face)) { LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, 0);
minlight = *value * 64.0f;
minlight_color = Face_LookupTextureColor(bsp, face);
}
} }
if (minlight) { if (auto value = IsSurfaceLitFace(bsp, face)) {
LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps); minlight = std::get<0>(value.value()) * 64.0f;
minlight_color = Face_LookupTextureColor(bsp, face);
LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, std::get<1>(value.value()));
} }
LightFace_LocalMin(bsp, face, &lightsurf, lightmaps);
/* negative lights */ /* negative lights */
if (!(modelinfo->lightignore.value() || extended_flags.light_ignore)) { if (!(modelinfo->lightignore.value() || extended_flags.light_ignore)) {
for (const auto &entity : GetLights()) { for (const auto &entity : GetLights()) {

View File

@ -141,20 +141,20 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys
surfacelightsByFacenum[Face_GetNum(bsp, face)].push_back(index); surfacelightsByFacenum[Face_GetNum(bsp, face)].push_back(index);
} }
std::optional<int32_t> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face) std::optional<std::tuple<int32_t, int32_t>> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face)
{ {
if (bsp->loadversion->game->id == GAME_QUAKE_II) { if (bsp->loadversion->game->id == GAME_QUAKE_II) {
// first, check if it's a Q2 surface // first, check if it's a Q2 surface
const mtexinfo_t *info = Face_Texinfo(bsp, face); const mtexinfo_t *info = Face_Texinfo(bsp, face);
if (info != nullptr && (info->flags.native & Q2_SURF_LIGHT) && info->value > 0) { if (info != nullptr && (info->flags.native & Q2_SURF_LIGHT) && info->value > 0) {
return info->value; return std::make_tuple(info->value, 0);
} }
} }
for (const auto &surflight : GetSurfaceLightTemplates()) { for (const auto &surflight : GetSurfaceLightTemplates()) {
if (FaceMatchesSurfaceLightTemplate(bsp, face, *surflight, SURFLIGHT_RAD)) { if (FaceMatchesSurfaceLightTemplate(bsp, face, *surflight, SURFLIGHT_RAD)) {
return surflight->light.value(); return std::make_tuple(surflight->light.value(), surflight->style.value());
} }
} }

View File

@ -435,7 +435,10 @@ void MakeTreePortals(tree_t *tree)
portalstats_t stats{}; portalstats_t stats{};
MakeHeadnodePortals(tree); MakeHeadnodePortals(tree);
MakeTreePortals_r(tree, tree->headnode.get(), stats); MakeTreePortals_r(tree, tree->headnode.get(), stats);
logging::print(logging::flag::STAT, " {:8} tiny portals\n", stats.c_tinyportals);
} }
static void AssertNoPortals_r(node_t *node) static void AssertNoPortals_r(node_t *node)