diff --git a/include/light/entities.hh b/include/light/entities.hh index efb0ea5c..1619fc02 100644 --- a/include/light/entities.hh +++ b/include/light/entities.hh @@ -130,13 +130,6 @@ const std::vector &GetSuns(); const std::vector> &GetSurfaceLightTemplates(); -enum { - // Q1-style surface light copies - SURFLIGHT_Q1 = 0, - // Q2/Q3-style radiosity - SURFLIGHT_RAD = 1 -}; - bool FaceMatchesSurfaceLightTemplate(const mbsp_t *bsp, const mface_t *face, const light_t &surflight, int surf_type); const entdict_t *FindEntDictWithKeyPair(const std::string &key, const std::string &value); diff --git a/include/light/light.hh b/include/light/light.hh index 12f392d2..b3358814 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -268,6 +268,13 @@ enum class visapprox_t // worldspawn keys / command-line settings // +enum { + // Q1-style surface light copies + SURFLIGHT_Q1 = 0, + // Q2/Q3-style radiosity + SURFLIGHT_RAD = 1 +}; + namespace settings { extern setting_group worldspawn_group; @@ -333,6 +340,7 @@ public: setting_scalar sun_deviance{this, "sunlight_penumbra", 0.0, 0.0, 180.0, &worldspawn_group}; setting_vec3 sky_surface{ this, {"sky_surface", "sun_surface"}, 0, 0, 0, &worldspawn_group} /* arghrad surface lights on sky faces */; + setting_int32 surflight_radiosity{this, "surflight_radiosity", SURFLIGHT_Q1, &worldspawn_group, "whether to use Q1-style surface subdivision (0) or Q2-style surface radiosity"}; }; extern setting_group output_group; diff --git a/light/entities.cc b/light/entities.cc index f5914add..42923307 100644 --- a/light/entities.cc +++ b/light/entities.cc @@ -1182,8 +1182,17 @@ static aabb3d BoundPoly(int numverts, qvec3d *verts) bool FaceMatchesSurfaceLightTemplate(const mbsp_t *bsp, const mface_t *face, const light_t &surflight, int surf_type) { const char *texname = Face_TextureName(bsp, face); + + int32_t radiosity_type; + + if (surflight.epairs->has("_surface_radiosity")) { + radiosity_type = surflight.epairs->get_int("_surface_radiosity"); + } else { + radiosity_type = options.surflight_radiosity.value(); + } + return !Q_strcasecmp(texname, surflight.epairs->get("_surface")) && - !!surflight.epairs->get_int("_surface_radiosity") == surf_type; + radiosity_type == surf_type; } /* diff --git a/light/surflight.cc b/light/surflight.cc index 677de38c..33a90bc9 100644 --- a/light/surflight.cc +++ b/light/surflight.cc @@ -46,53 +46,8 @@ std::vector surfacelights; std::map> surfacelightsByFacenum; int total_surflight_points = 0; -static void MakeSurfaceLightsThread(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, size_t i) +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) { - const mface_t *face = BSP_GetFace(bsp, i); - - // Face casts light? - - int32_t light_value = 0; - bool is_sky = false, is_directional = false; - int32_t style = 0; - std::optional texture_color; - - if (bsp->loadversion->game->id == GAME_QUAKE_II) { - // first, check if it's a Q2 surface - const mtexinfo_t *info = Face_Texinfo(bsp, face); - - if (info == nullptr) - return; - - if (!(info->flags.native & Q2_SURF_LIGHT) || info->value == 0) { - if (info->flags.native & Q2_SURF_LIGHT) { - qvec3d wc = winding_t::from_face(bsp, face).center(); - logging::print("WARNING: surface light '{}' at [{}] has 0 intensity.\n", Face_TextureName(bsp, face), wc); - } - return; - } - - light_value = info->value; - is_sky = (info->flags.native & Q2_SURF_SKY); - } - - // check matching templates - if (!light_value) { - for (const auto &surflight : GetSurfaceLightTemplates()) { - if (FaceMatchesSurfaceLightTemplate(bsp, face, *surflight, SURFLIGHT_RAD)) { - light_value = surflight->light.value(); - is_sky = surflight->epairs->get_int("_surface_is_sky"); - is_directional = !!surflight->epairs->get_int("_surface_spotlight"); - style = surflight->epairs->get_int("style"); - - if (surflight->color.isChanged()) { - texture_color = surflight->color.value() / 255.f; - } - break; - } - } - } - // Create face points... auto poly = GLM_FacePoints(bsp, face); const float facearea = qv::PolyArea(poly.begin(), poly.end()); @@ -176,6 +131,45 @@ static void MakeSurfaceLightsThread(const mbsp_t *bsp, const settings::worldspaw surfacelightsByFacenum[Face_GetNum(bsp, face)].push_back(index); } +static void MakeSurfaceLightsThread(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, size_t i) +{ + const mface_t *face = BSP_GetFace(bsp, i); + + // Face casts light? + + if (bsp->loadversion->game->id == GAME_QUAKE_II) { + // first, check if it's a Q2 surface + const mtexinfo_t *info = Face_Texinfo(bsp, face); + + if (info == nullptr) + return; + + if (!(info->flags.native & Q2_SURF_LIGHT) || info->value == 0) { + if (info->flags.native & Q2_SURF_LIGHT) { + qvec3d wc = winding_t::from_face(bsp, face).center(); + logging::print("WARNING: surface light '{}' at [{}] has 0 intensity.\n", Face_TextureName(bsp, face), wc); + } + return; + } + + MakeSurfaceLight(bsp, cfg, face, std::nullopt, false, (info->flags.native & Q2_SURF_SKY), 0, info->value); + } + + // check matching templates + for (const auto &surflight : GetSurfaceLightTemplates()) { + if (FaceMatchesSurfaceLightTemplate(bsp, face, *surflight, SURFLIGHT_RAD)) { + std::optional texture_color; + + if (surflight->color.isChanged()) { + texture_color = surflight->color.value() / 255.f; + } + + MakeSurfaceLight(bsp, cfg, face, texture_color, !!surflight->epairs->get_int("_surface_spotlight"), + surflight->epairs->get_int("_surface_is_sky"), surflight->epairs->get_int("style"), surflight->light.value()); + } + } +} + const std::vector &SurfaceLights() { return surfacelights;