diff --git a/common/bspfile.cc b/common/bspfile.cc index 4ad0ad4f..425d7f2e 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -348,7 +348,27 @@ public: this->id = ID; } - bool surf_is_lightmapped(const surfflags_t &flags) const override { return !(flags.native & TEX_SPECIAL); } + bool surf_is_lightmapped(const surfflags_t &flags, const char *texname, bool light_nodraw, bool lightgrid_enabled) const override + { + /* don't save lightmaps for "trigger" texture */ + if (!Q_strcasecmp(texname, "trigger")) + return false; + + /* don't save lightmaps for "skip" texture */ + if (!Q_strcasecmp(texname, "skip")) + return false; + + return !(flags.native & TEX_SPECIAL); + } + + bool surf_is_emissive(const surfflags_t &flags, const char *texname) const override + { + /* don't save lightmaps for "trigger" texture */ + if (!Q_strcasecmp(texname, "trigger")) + return false; + + return true; + } bool surf_is_subdivided(const surfflags_t &flags) const override { return !(flags.native & TEX_SPECIAL); } @@ -956,11 +976,26 @@ struct gamedef_q2_t : public gamedef_t max_entity_key = 256; } - bool surf_is_lightmapped(const surfflags_t &flags) const override - { + bool surf_is_lightmapped(const surfflags_t &flags, const char *texname, bool light_nodraw, bool lightgrid_enabled) const override + { // Q2RTX should light nodraw faces + if (light_nodraw && (flags.native & Q2_SURF_NODRAW)) { + return true; + } + + // The only reason to lightmap sky faces in Q2 is to light models floating over sky. + // If lightgrid is in use, this reason is no longer relevant, so skip lightmapping. + if (lightgrid_enabled && (flags.native & Q2_SURF_SKY)) { + return false; + } + return !(flags.native & (Q2_SURF_NODRAW | Q2_SURF_SKIP)); } + bool surf_is_emissive(const surfflags_t &flags, const char *texname) const override + { + return true; + } + bool surf_is_subdivided(const surfflags_t &flags) const override { return !(flags.native & Q2_SURF_SKY); } bool surfflags_are_valid(const surfflags_t &flags) const override diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index 056f1b13..2b925615 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -287,7 +287,10 @@ struct gamedef_t gamedef_t(const char *default_base_dir); - virtual bool surf_is_lightmapped(const surfflags_t &flags) const = 0; + // surface stores lightmap/luxel color data + virtual bool surf_is_lightmapped(const surfflags_t &flags, const char *texname, bool light_nodraw, bool lightgrid_enabled) const = 0; + // surface can be emissive + virtual bool surf_is_emissive(const surfflags_t &flags, const char *texname) const = 0; virtual bool surf_is_subdivided(const surfflags_t &flags) const = 0; virtual bool surfflags_are_valid(const surfflags_t &flags) const = 0; /** diff --git a/include/light/light.hh b/include/light/light.hh index 3e19f628..dd66d570 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -117,7 +117,7 @@ struct lightsurf_t qvec3d tnormal; /* 16 in vanilla. engines will hate you if this is not power-of-two-and-at-least-one */ - float lightmapscale; + float lightmapscale = 0.f; faceextents_t extents, vanilla_extents; diff --git a/include/light/ltface.hh b/include/light/ltface.hh index 4af61294..2623f235 100644 --- a/include/light/ltface.hh +++ b/include/light/ltface.hh @@ -51,6 +51,7 @@ void SetupDirt(settings::worldspawn_keys &cfg); std::unique_ptr CreateLightmapSurface(const mbsp_t *bsp, const mface_t *face, const facesup_t *facesup, const bspx_decoupled_lm_perface *facesup_decoupled, const settings::worldspawn_keys &cfg); bool Face_IsLightmapped(const mbsp_t *bsp, const mface_t *face); +bool Face_IsEmissive(const mbsp_t *bsp, const mface_t *face); void DirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::worldspawn_keys &cfg); void IndirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::worldspawn_keys &cfg); void PostProcessLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::worldspawn_keys &cfg); diff --git a/light/bounce.cc b/light/bounce.cc index e641e7ae..e3bcdde5 100644 --- a/light/bounce.cc +++ b/light/bounce.cc @@ -90,6 +90,10 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys & qvec3d texture_color, int32_t style, const std::vector &points, const winding_t &winding, const vec_t &area, const qvec3d &facenormal, const qvec3d &facemidpoint) { + if (!Face_IsEmissive(bsp, surf.face)) { + return; + } + bouncelightpoints += points.size(); // Calculate emit color and intensity... diff --git a/light/light.cc b/light/light.cc index baa3653b..308619b1 100644 --- a/light/light.cc +++ b/light/light.cc @@ -709,7 +709,7 @@ static void SaveLightmapSurfaces(mbsp_t *bsp) logging::parallel_for(static_cast(0), bsp->dfaces.size(), [&bsp](size_t i) { auto &surf = light_surfaces[i]; - if (!surf) { + if (!surf || surf->samples.empty()) { return; } @@ -920,7 +920,7 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale) logging::header("Direct Lighting"); // mxd logging::parallel_for(static_cast(0), bsp.dfaces.size(), [&bsp](size_t i) { - if (light_surfaces[i]) { + if (light_surfaces[i] && Face_IsLightmapped(&bsp, &bsp.dfaces[i])) { #if defined(HAVE_EMBREE) && defined(__SSE2__) _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); #endif @@ -934,7 +934,7 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale) logging::header("Indirect Lighting"); // mxd logging::parallel_for(static_cast(0), bsp.dfaces.size(), [&bsp](size_t i) { - if (light_surfaces[i]) { + if (light_surfaces[i] && Face_IsLightmapped(&bsp, &bsp.dfaces[i])) { #if defined(HAVE_EMBREE) && defined(__SSE2__) _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); #endif @@ -947,7 +947,7 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale) if (!light_options.nolighting.value()) { logging::header("Post-Processing"); // mxd logging::parallel_for(static_cast(0), bsp.dfaces.size(), [&bsp](size_t i) { - if (light_surfaces[i]) { + if (light_surfaces[i] && Face_IsLightmapped(&bsp, &bsp.dfaces[i])) { #if defined(HAVE_EMBREE) && defined(__SSE2__) _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); #endif diff --git a/light/ltface.cc b/light/ltface.cc index 3143498f..9c115c94 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -589,150 +589,154 @@ static std::unique_ptr Lightsurf_Init(const modelinfo_t *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 (Face_IsLightmapped(bsp, 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); - // pick the larger of the two scales - lightsurf->lightmapscale = - (facesup && facesup->lmscale < modelinfo->lightmapscale) ? facesup->lmscale : 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 || Q2_FacePhongValue(bsp, face); + const surfflags_t &extended_flags = extended_texinfo_flags[face->texinfo]; + lightsurf->curved = extended_flags.phong_angle != 0 || Q2_FacePhongValue(bsp, face); - // nodirt - if (modelinfo->dirt.is_changed()) { - lightsurf->nodirt = (modelinfo->dirt.value() == -1); - } else { - lightsurf->nodirt = extended_flags.no_dirt; - } + // nodirt + if (modelinfo->dirt.is_changed()) { + lightsurf->nodirt = (modelinfo->dirt.value() == -1); + } else { + lightsurf->nodirt = extended_flags.no_dirt; + } - // minlight - if (modelinfo->minlight.is_changed()) { - lightsurf->minlight = modelinfo->minlight.value(); - } else if (extended_flags.minlight) { - lightsurf->minlight = *extended_flags.minlight; - } else { - lightsurf->minlight = light_options.minlight.value(); - } + // minlight + if (modelinfo->minlight.is_changed()) { + lightsurf->minlight = modelinfo->minlight.value(); + } else if (extended_flags.minlight) { + lightsurf->minlight = *extended_flags.minlight; + } else { + lightsurf->minlight = light_options.minlight.value(); + } - // minlightMottle - if (modelinfo->minlightMottle.is_changed()) { - lightsurf->minlightMottle = modelinfo->minlightMottle.value(); - } else if (light_options.minlightMottle.is_changed()) { - lightsurf->minlightMottle = light_options.minlightMottle.value(); - } else { - // default value depends on game + // minlightMottle + if (modelinfo->minlightMottle.is_changed()) { + lightsurf->minlightMottle = modelinfo->minlightMottle.value(); + } else if (light_options.minlightMottle.is_changed()) { + lightsurf->minlightMottle = light_options.minlightMottle.value(); + } else { + // default value depends on game + if (bsp->loadversion->game->id == GAME_QUAKE_II) { + lightsurf->minlightMottle = true; + } else { + lightsurf->minlightMottle = false; + } + } + + // Q2 uses a 0-1 range for minlight if (bsp->loadversion->game->id == GAME_QUAKE_II) { - lightsurf->minlightMottle = true; - } else { - lightsurf->minlightMottle = false; + lightsurf->minlight *= 128.f; } - } - // Q2 uses a 0-1 range for minlight - if (bsp->loadversion->game->id == GAME_QUAKE_II) { - lightsurf->minlight *= 128.f; - } - - // maxlight - if (modelinfo->maxlight.is_changed()) { - lightsurf->maxlight = modelinfo->maxlight.value(); - } else { - lightsurf->maxlight = extended_flags.maxlight; - } - - // lightcolorscale - if (modelinfo->lightcolorscale.is_changed()) { - lightsurf->lightcolorscale = modelinfo->lightcolorscale.value(); - } else { - lightsurf->lightcolorscale = extended_flags.lightcolorscale; - } - - // Q2 uses a 0-1 range for minlight - if (bsp->loadversion->game->id == GAME_QUAKE_II) { - lightsurf->maxlight *= 128.f; - } - - // minlight_color - if (modelinfo->minlight_color.is_changed()) { - lightsurf->minlight_color = modelinfo->minlight_color.value(); - } else if (!qv::emptyExact(extended_flags.minlight_color)) { - lightsurf->minlight_color = extended_flags.minlight_color; - } else { - lightsurf->minlight_color = light_options.minlight_color.value(); - } - - /* never receive dirtmapping on lit liquids */ - if (Face_IsTranslucent(bsp, face)) { - lightsurf->nodirt = true; - } - - /* handle glass alpha */ - if (modelinfo->alpha.value() < 1) { - /* skip culling of rays coming from the back side of the face */ - lightsurf->twosided = true; - } - - /* object channel mask */ - if (extended_flags.object_channel_mask) { - lightsurf->object_channel_mask = *extended_flags.object_channel_mask; - } else { - lightsurf->object_channel_mask = modelinfo->object_channel_mask.value(); - } - - if (extended_flags.surflight_minlight_scale) { - lightsurf->surflight_minlight_scale = *extended_flags.surflight_minlight_scale; - } else { - lightsurf->surflight_minlight_scale = 1.0f; - } - - /* Set up the plane, not including model offset */ - qplane3d &plane = lightsurf->plane; - if (face->side) { - plane = -bsp->dplanes[face->planenum]; - } else { - plane = bsp->dplanes[face->planenum]; - } - - 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 */ - if (light_options.world_units_per_luxel.is_changed()) { - if (bsp->loadversion->game->id == GAME_QUAKE_II && (Face_Texinfo(bsp, face)->flags.native & Q2_SURF_SKY)) { - lightsurf->extents = faceextents_t(*face, *bsp, world_units_per_luxel_t{}, 512.f); - } else if (extended_flags.world_units_per_luxel) { - lightsurf->extents = - faceextents_t(*face, *bsp, world_units_per_luxel_t{}, *extended_flags.world_units_per_luxel); + // maxlight + if (modelinfo->maxlight.is_changed()) { + lightsurf->maxlight = modelinfo->maxlight.value(); } else { - lightsurf->extents = - faceextents_t(*face, *bsp, world_units_per_luxel_t{}, light_options.world_units_per_luxel.value()); + lightsurf->maxlight = extended_flags.maxlight; } - } else { - lightsurf->extents = faceextents_t(*face, *bsp, lightsurf->lightmapscale); + + // lightcolorscale + if (modelinfo->lightcolorscale.is_changed()) { + lightsurf->lightcolorscale = modelinfo->lightcolorscale.value(); + } else { + lightsurf->lightcolorscale = extended_flags.lightcolorscale; + } + + // Q2 uses a 0-1 range for minlight + if (bsp->loadversion->game->id == GAME_QUAKE_II) { + lightsurf->maxlight *= 128.f; + } + + // minlight_color + if (modelinfo->minlight_color.is_changed()) { + lightsurf->minlight_color = modelinfo->minlight_color.value(); + } else if (!qv::emptyExact(extended_flags.minlight_color)) { + lightsurf->minlight_color = extended_flags.minlight_color; + } else { + lightsurf->minlight_color = light_options.minlight_color.value(); + } + + /* never receive dirtmapping on lit liquids */ + if (Face_IsTranslucent(bsp, face)) { + lightsurf->nodirt = true; + } + + /* handle glass alpha */ + if (modelinfo->alpha.value() < 1) { + /* skip culling of rays coming from the back side of the face */ + lightsurf->twosided = true; + } + + /* object channel mask */ + if (extended_flags.object_channel_mask) { + lightsurf->object_channel_mask = *extended_flags.object_channel_mask; + } else { + lightsurf->object_channel_mask = modelinfo->object_channel_mask.value(); + } + + if (extended_flags.surflight_minlight_scale) { + lightsurf->surflight_minlight_scale = *extended_flags.surflight_minlight_scale; + } else { + lightsurf->surflight_minlight_scale = 1.0f; + } + + /* Set up the plane, not including model offset */ + qplane3d &plane = lightsurf->plane; + if (face->side) { + plane = -bsp->dplanes[face->planenum]; + } else { + plane = bsp->dplanes[face->planenum]; + } + + 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 */ + if (light_options.world_units_per_luxel.is_changed()) { + if (bsp->loadversion->game->id == GAME_QUAKE_II && (Face_Texinfo(bsp, face)->flags.native & Q2_SURF_SKY)) { + lightsurf->extents = faceextents_t(*face, *bsp, world_units_per_luxel_t{}, 512.f); + } else if (extended_flags.world_units_per_luxel) { + lightsurf->extents = + faceextents_t(*face, *bsp, world_units_per_luxel_t{}, *extended_flags.world_units_per_luxel); + } else { + lightsurf->extents = + faceextents_t(*face, *bsp, world_units_per_luxel_t{}, light_options.world_units_per_luxel.value()); + } + } else { + lightsurf->extents = faceextents_t(*face, *bsp, lightsurf->lightmapscale); + } + lightsurf->vanilla_extents = faceextents_t(*face, *bsp, LMSCALE_DEFAULT); + + 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) */ + qvec3d planepoint = (plane.normal * plane.dist) + modelinfo->offset; + plane.dist = qv::dot(plane.normal, planepoint); + + /* Correct bounding sphere */ + lightsurf->extents.origin += modelinfo->offset; + lightsurf->extents.bounds = lightsurf->extents.bounds.translate(modelinfo->offset); + + lightsurf->intersection_stream.resize(lightsurf->samples.size()); + lightsurf->occlusion_stream.resize(lightsurf->samples.size()); + + /* Setup vis data */ + CalcPvs(bsp, lightsurf.get()); } - lightsurf->vanilla_extents = faceextents_t(*face, *bsp, LMSCALE_DEFAULT); - 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) */ - qvec3d planepoint = (plane.normal * plane.dist) + modelinfo->offset; - plane.dist = qv::dot(plane.normal, planepoint); - - /* Correct bounding sphere */ - lightsurf->extents.origin += modelinfo->offset; - lightsurf->extents.bounds = lightsurf->extents.bounds.translate(modelinfo->offset); - - lightsurf->intersection_stream.resize(lightsurf->samples.size()); - lightsurf->occlusion_stream.resize(lightsurf->samples.size()); - - /* Setup vis data */ - CalcPvs(bsp, lightsurf.get()); + // emissiveness is handled later and allocated only if necessary return lightsurf; } @@ -802,8 +806,10 @@ static void Lightmap_ClearAll(lightmapdict_t *lightmaps) * otherwise emit a warning. */ static void Lightmap_Save( - lightmapdict_t *lightmaps, const lightsurf_t *lightsurf, lightmap_t *lightmap, const int style) + const mbsp_t *bsp, lightmapdict_t *lightmaps, const lightsurf_t *lightsurf, lightmap_t *lightmap, const int style) { + Q_assert(Face_IsLightmapped(bsp, lightsurf->face)); + if (lightmap->style == INVALID_LIGHTSTYLE) { lightmap->style = style; } @@ -1294,7 +1300,7 @@ static void LightFace_Entity( sample.color += rs.getPushedRayColor(j); sample.direction += rs.getPushedRayNormalContrib(j); - Lightmap_Save(lightmaps, lightsurf, cached_lightmap, cached_style); + Lightmap_Save(bsp, lightmaps, lightsurf, cached_lightmap, cached_style); } } @@ -1360,7 +1366,7 @@ static void LightPoint_Entity(const mbsp_t *bsp, raystream_occlusion_t &rs, cons * LightFace_Sky * ============= */ -static void LightFace_Sky(const sun_t *sun, lightsurf_t *lightsurf, lightmapdict_t *lightmaps) +static void LightFace_Sky(const mbsp_t *bsp, const sun_t *sun, lightsurf_t *lightsurf, lightmapdict_t *lightmaps) { const settings::worldspawn_keys &cfg = *lightsurf->cfg; const modelinfo_t *modelinfo = lightsurf->modelinfo; @@ -1467,7 +1473,7 @@ static void LightFace_Sky(const sun_t *sun, lightsurf_t *lightsurf, lightmapdict sample.direction += rs.getPushedRayNormalContrib(j); total_light_ray_hits++; - Lightmap_Save(lightmaps, lightsurf, cached_lightmap, cached_style); + Lightmap_Save(bsp, lightmaps, lightsurf, cached_lightmap, cached_style); } } @@ -1672,7 +1678,7 @@ static void LightFace_Min(const mbsp_t *bsp, const mface_t *face, const qvec3d & } if (hit) { - Lightmap_Save(lightmaps, lightsurf, lightmap, style); + Lightmap_Save(bsp, lightmaps, lightsurf, lightmap, style); } } @@ -1753,7 +1759,7 @@ static void LightFace_LocalMin( } if (hit) { - Lightmap_Save(lightmaps, lightsurf, lightmap, entity->style.value()); + Lightmap_Save(bsp, lightmaps, lightsurf, lightmap, entity->style.value()); } } } @@ -1818,7 +1824,7 @@ static void LightFace_AutoMin(const mbsp_t *bsp, const mface_t *face, lightsurf_ } } - Lightmap_Save(lightmaps, lightsurf, lightmap, grid_sample.style); + Lightmap_Save(bsp, lightmaps, lightsurf, lightmap, grid_sample.style); } // clear occluded state, since we filled in all occluded samples with a color @@ -1833,7 +1839,7 @@ static void LightFace_AutoMin(const mbsp_t *bsp, const mface_t *face, lightsurf_ * LightFace_DirtDebug * ============= */ -static void LightFace_DirtDebug(const lightsurf_t *lightsurf, lightmapdict_t *lightmaps) +static void LightFace_DirtDebug(const mbsp_t *bsp, const lightsurf_t *lightsurf, lightmapdict_t *lightmaps) { const settings::worldspawn_keys &cfg = *lightsurf->cfg; /* use a style 0 light map */ @@ -1846,7 +1852,7 @@ static void LightFace_DirtDebug(const lightsurf_t *lightsurf, lightmapdict_t *li sample.color = {light}; } - Lightmap_Save(lightmaps, lightsurf, lightmap, 0); + Lightmap_Save(bsp, lightmaps, lightsurf, lightmap, 0); } /* @@ -1854,7 +1860,7 @@ static void LightFace_DirtDebug(const lightsurf_t *lightsurf, lightmapdict_t *li * LightFace_PhongDebug * ============= */ -static void LightFace_PhongDebug(const lightsurf_t *lightsurf, lightmapdict_t *lightmaps) +static void LightFace_PhongDebug(const mbsp_t *bsp, const lightsurf_t *lightsurf, lightmapdict_t *lightmaps) { /* use a style 0 light map */ lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, 0, lightsurf); @@ -1870,10 +1876,10 @@ static void LightFace_PhongDebug(const lightsurf_t *lightsurf, lightmapdict_t *l } } - Lightmap_Save(lightmaps, lightsurf, lightmap, 0); + Lightmap_Save(bsp, lightmaps, lightsurf, lightmap, 0); } -static void LightFace_DebugMottle(const lightsurf_t *lightsurf, lightmapdict_t *lightmaps) +static void LightFace_DebugMottle(const mbsp_t *bsp, const lightsurf_t *lightsurf, lightmapdict_t *lightmaps) { /* use a style 0 light map */ lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, 0, lightsurf); @@ -1887,7 +1893,7 @@ static void LightFace_DebugMottle(const lightsurf_t *lightsurf, lightmapdict_t * sample.color = qvec3f(minlight + Mottle(lightsurf->samples[i].point)); } - Lightmap_Save(lightmaps, lightsurf, lightmap, 0); + Lightmap_Save(bsp, lightmaps, lightsurf, lightmap, 0); } // mxd. Surface light falloff. Returns color in [0,255] @@ -2067,7 +2073,7 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t // If surface light contributed anything, save. if (hit) - Lightmap_Save(lightmaps, lightsurf, lightmap, lightmapstyle); + Lightmap_Save(bsp, lightmaps, lightsurf, lightmap, lightmapstyle); } } } @@ -2157,7 +2163,7 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector *pvs, rays } } -static void LightFace_OccludedDebug(lightsurf_t *lightsurf, lightmapdict_t *lightmaps) +static void LightFace_OccludedDebug(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps) { Q_assert(light_options.debugmode == debugmodes::debugoccluded); @@ -2177,10 +2183,10 @@ static void LightFace_OccludedDebug(lightsurf_t *lightsurf, lightmapdict_t *ligh surf_sample.occluded = false; } - Lightmap_Save(lightmaps, lightsurf, lightmap, 0); + Lightmap_Save(bsp, lightmaps, lightsurf, lightmap, 0); } -static void LightFace_DebugNeighbours(lightsurf_t *lightsurf, lightmapdict_t *lightmaps) +static void LightFace_DebugNeighbours(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps) { Q_assert(light_options.debugmode == debugmodes::debugneighbours); @@ -2219,7 +2225,7 @@ static void LightFace_DebugNeighbours(lightsurf_t *lightsurf, lightmapdict_t *li lightsurf->samples[i].occluded = false; } - Lightmap_Save(lightmaps, lightsurf, lightmap, 0); + Lightmap_Save(bsp, lightmaps, lightsurf, lightmap, 0); } /* Dirtmapping borrowed from q3map2, originally by RaP7oR */ @@ -2828,28 +2834,34 @@ static std::vector BoxBlurImage(const std::vector &input, int w, return res; } +// check if the given face can actually store luxel data bool Face_IsLightmapped(const mbsp_t *bsp, const mface_t *face) { const mtexinfo_t *texinfo = Face_Texinfo(bsp, face); - if (texinfo == nullptr) + if (texinfo == nullptr) { return false; - - // Q2RTX should light nodraw faces - if (light_options.q2rtx.value() && bsp->loadversion->game->id == GAME_QUAKE_II && - (texinfo->flags.native & Q2_SURF_NODRAW)) { - return true; } - // 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. - // TEMP DISABLED - /*if (light_options.lightgrid.value() && bsp->loadversion->game->id == GAME_QUAKE_II && - (texinfo->flags.native & Q2_SURF_SKY)) { - return false; - }*/ + const char *texname = Face_TextureName(bsp, face); - return bsp->loadversion->game->surf_is_lightmapped(texinfo->flags); + return bsp->loadversion->game->surf_is_lightmapped(texinfo->flags, texname, + light_options.q2rtx.value() && bsp->loadversion->game->id == GAME_QUAKE_II, // FIXME: move to own config option. -light_nodraw? + light_options.lightgrid.value()); +} + +// check if the given face can actually emit light +bool Face_IsEmissive(const mbsp_t *bsp, const mface_t *face) +{ + const mtexinfo_t *texinfo = Face_Texinfo(bsp, face); + + if (texinfo == nullptr) { + return false; + } + + const char *texname = Face_TextureName(bsp, face); + + return bsp->loadversion->game->surf_is_emissive(texinfo->flags, texname); } /** @@ -3222,8 +3234,6 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, { const char *texname = Face_TextureName(bsp, face); Q_assert(Face_IsLightmapped(bsp, face)); - Q_assert(Q_strcasecmp(texname, "skip") != 0); - Q_assert(Q_strcasecmp(texname, "trigger") != 0); } for (int mapnum = 0; mapnum < numstyles; mapnum++) { @@ -3287,18 +3297,10 @@ std::unique_ptr CreateLightmapSurface(const mbsp_t *bsp, const mfac if (face->numedges < 3) return nullptr; - if (!Face_IsLightmapped(bsp, face)) - return nullptr; - - const char *texname = Face_TextureName(bsp, face); - - /* don't save lightmaps for "trigger" texture */ - if (!Q_strcasecmp(texname, "trigger")) - return nullptr; - - /* don't save lightmaps for "skip" texture */ - if (!Q_strcasecmp(texname, "skip")) + // if we don't have a lightmap or emissive, we're done + if (!Face_IsEmissive(bsp, face) && !Face_IsLightmapped(bsp, face)) { return nullptr; + } return Lightsurf_Init(modelinfo, cfg, face, bsp, facesup, facesup_decoupled); } @@ -3343,7 +3345,7 @@ void DirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings:: } for (const sun_t &sun : GetSuns()) if (sun.sunlight > 0) - LightFace_Sky(&sun, &lightsurf, lightmaps); + LightFace_Sky(bsp, &sun, &lightsurf, lightmaps); // mxd. Add surface lights... // FIXME: negative surface lights @@ -3356,16 +3358,16 @@ void DirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings:: /* replace lightmaps with AO for debugging */ if (light_options.debugmode == debugmodes::dirt) - LightFace_DirtDebug(&lightsurf, lightmaps); + LightFace_DirtDebug(bsp, &lightsurf, lightmaps); if (light_options.debugmode == debugmodes::phong) - LightFace_PhongDebug(&lightsurf, lightmaps); + LightFace_PhongDebug(bsp, &lightsurf, lightmaps); if (light_options.debugmode == debugmodes::debugoccluded) - LightFace_OccludedDebug(&lightsurf, lightmaps); + LightFace_OccludedDebug(bsp, &lightsurf, lightmaps); if (light_options.debugmode == debugmodes::debugneighbours) - LightFace_DebugNeighbours(&lightsurf, lightmaps); + LightFace_DebugNeighbours(bsp, &lightsurf, lightmaps); } /* @@ -3457,12 +3459,12 @@ void PostProcessLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const setti } for (const sun_t &sun : GetSuns()) if (sun.sunlight < 0) - LightFace_Sky(&sun, &lightsurf, lightmaps); + LightFace_Sky(bsp, &sun, &lightsurf, lightmaps); } } if (light_options.debugmode == debugmodes::mottle) - LightFace_DebugMottle(&lightsurf, lightmaps); + LightFace_DebugMottle(bsp, &lightsurf, lightmaps); } // lightgrid diff --git a/light/surflight.cc b/light/surflight.cc index 6c8f4cf5..d4b69d4a 100644 --- a/light/surflight.cc +++ b/light/surflight.cc @@ -57,7 +57,7 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys { auto &surf_ptr = LightSurfaces()[face - bsp->dfaces.data()]; - if (!surf_ptr) { + if (!surf_ptr || !Face_IsEmissive(bsp, face)) { return; }