decouple lightmapping state from emissive state

allow sky to skip lightmapping if lightgrid is enabled in Q2 mode again
This commit is contained in:
Jonathan 2023-06-19 04:11:20 -04:00
parent 94357818f9
commit 1fbe12767e
8 changed files with 239 additions and 194 deletions

View File

@ -348,7 +348,27 @@ public:
this->id = ID; 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); } 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; 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)); 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 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 bool surfflags_are_valid(const surfflags_t &flags) const override

View File

@ -287,7 +287,10 @@ struct gamedef_t
gamedef_t(const char *default_base_dir); 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 surf_is_subdivided(const surfflags_t &flags) const = 0;
virtual bool surfflags_are_valid(const surfflags_t &flags) const = 0; virtual bool surfflags_are_valid(const surfflags_t &flags) const = 0;
/** /**

View File

@ -117,7 +117,7 @@ struct lightsurf_t
qvec3d tnormal; qvec3d tnormal;
/* 16 in vanilla. engines will hate you if this is not power-of-two-and-at-least-one */ /* 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; faceextents_t extents, vanilla_extents;

View File

@ -51,6 +51,7 @@ void SetupDirt(settings::worldspawn_keys &cfg);
std::unique_ptr<lightsurf_t> CreateLightmapSurface(const mbsp_t *bsp, const mface_t *face, const facesup_t *facesup, std::unique_ptr<lightsurf_t> 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); 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_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 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 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); void PostProcessLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::worldspawn_keys &cfg);

View File

@ -90,6 +90,10 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &
qvec3d texture_color, int32_t style, const std::vector<qvec3f> &points, const winding_t &winding, const vec_t &area, qvec3d texture_color, int32_t style, const std::vector<qvec3f> &points, const winding_t &winding, const vec_t &area,
const qvec3d &facenormal, const qvec3d &facemidpoint) const qvec3d &facenormal, const qvec3d &facemidpoint)
{ {
if (!Face_IsEmissive(bsp, surf.face)) {
return;
}
bouncelightpoints += points.size(); bouncelightpoints += points.size();
// Calculate emit color and intensity... // Calculate emit color and intensity...

View File

@ -709,7 +709,7 @@ static void SaveLightmapSurfaces(mbsp_t *bsp)
logging::parallel_for(static_cast<size_t>(0), bsp->dfaces.size(), [&bsp](size_t i) { logging::parallel_for(static_cast<size_t>(0), bsp->dfaces.size(), [&bsp](size_t i) {
auto &surf = light_surfaces[i]; auto &surf = light_surfaces[i];
if (!surf) { if (!surf || surf->samples.empty()) {
return; return;
} }
@ -920,7 +920,7 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
logging::header("Direct Lighting"); // mxd logging::header("Direct Lighting"); // mxd
logging::parallel_for(static_cast<size_t>(0), bsp.dfaces.size(), [&bsp](size_t i) { logging::parallel_for(static_cast<size_t>(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__) #if defined(HAVE_EMBREE) && defined(__SSE2__)
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
#endif #endif
@ -934,7 +934,7 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
logging::header("Indirect Lighting"); // mxd logging::header("Indirect Lighting"); // mxd
logging::parallel_for(static_cast<size_t>(0), bsp.dfaces.size(), [&bsp](size_t i) { logging::parallel_for(static_cast<size_t>(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__) #if defined(HAVE_EMBREE) && defined(__SSE2__)
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
#endif #endif
@ -947,7 +947,7 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
if (!light_options.nolighting.value()) { if (!light_options.nolighting.value()) {
logging::header("Post-Processing"); // mxd logging::header("Post-Processing"); // mxd
logging::parallel_for(static_cast<size_t>(0), bsp.dfaces.size(), [&bsp](size_t i) { logging::parallel_for(static_cast<size_t>(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__) #if defined(HAVE_EMBREE) && defined(__SSE2__)
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
#endif #endif

View File

@ -589,150 +589,154 @@ static std::unique_ptr<lightsurf_t> Lightsurf_Init(const modelinfo_t *modelinfo,
lightsurf->bsp = bsp; lightsurf->bsp = bsp;
lightsurf->face = face; lightsurf->face = face;
/* if liquid doesn't have the TEX_SPECIAL flag set, the map was qbsp'ed with if (Face_IsLightmapped(bsp, face)) {
* lit water in mind. In that case receive light from both top and bottom. /* if liquid doesn't have the TEX_SPECIAL flag set, the map was qbsp'ed with
* (lit will only be rendered in compatible engines, but degrades gracefully.) * 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); */
lightsurf->twosided = Face_IsTranslucent(bsp, face);
// pick the larger of the two scales // pick the larger of the two scales
lightsurf->lightmapscale = lightsurf->lightmapscale =
(facesup && facesup->lmscale < modelinfo->lightmapscale) ? facesup->lmscale : modelinfo->lightmapscale; (facesup && facesup->lmscale < modelinfo->lightmapscale) ? facesup->lmscale : modelinfo->lightmapscale;
const surfflags_t &extended_flags = extended_texinfo_flags[face->texinfo]; const surfflags_t &extended_flags = extended_texinfo_flags[face->texinfo];
lightsurf->curved = extended_flags.phong_angle != 0 || Q2_FacePhongValue(bsp, face); lightsurf->curved = extended_flags.phong_angle != 0 || Q2_FacePhongValue(bsp, face);
// nodirt // nodirt
if (modelinfo->dirt.is_changed()) { if (modelinfo->dirt.is_changed()) {
lightsurf->nodirt = (modelinfo->dirt.value() == -1); lightsurf->nodirt = (modelinfo->dirt.value() == -1);
} else { } else {
lightsurf->nodirt = extended_flags.no_dirt; lightsurf->nodirt = extended_flags.no_dirt;
} }
// minlight // minlight
if (modelinfo->minlight.is_changed()) { if (modelinfo->minlight.is_changed()) {
lightsurf->minlight = modelinfo->minlight.value(); lightsurf->minlight = modelinfo->minlight.value();
} else if (extended_flags.minlight) { } else if (extended_flags.minlight) {
lightsurf->minlight = *extended_flags.minlight; lightsurf->minlight = *extended_flags.minlight;
} else { } else {
lightsurf->minlight = light_options.minlight.value(); lightsurf->minlight = light_options.minlight.value();
} }
// minlightMottle // minlightMottle
if (modelinfo->minlightMottle.is_changed()) { if (modelinfo->minlightMottle.is_changed()) {
lightsurf->minlightMottle = modelinfo->minlightMottle.value(); lightsurf->minlightMottle = modelinfo->minlightMottle.value();
} else if (light_options.minlightMottle.is_changed()) { } else if (light_options.minlightMottle.is_changed()) {
lightsurf->minlightMottle = light_options.minlightMottle.value(); lightsurf->minlightMottle = light_options.minlightMottle.value();
} else { } else {
// default value depends on game // 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) { if (bsp->loadversion->game->id == GAME_QUAKE_II) {
lightsurf->minlightMottle = true; lightsurf->minlight *= 128.f;
} else {
lightsurf->minlightMottle = false;
} }
}
// Q2 uses a 0-1 range for minlight // maxlight
if (bsp->loadversion->game->id == GAME_QUAKE_II) { if (modelinfo->maxlight.is_changed()) {
lightsurf->minlight *= 128.f; lightsurf->maxlight = modelinfo->maxlight.value();
}
// 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);
} else { } else {
lightsurf->extents = lightsurf->maxlight = extended_flags.maxlight;
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); // 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); // emissiveness is handled later and allocated only if necessary
/* 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());
return lightsurf; return lightsurf;
} }
@ -802,8 +806,10 @@ static void Lightmap_ClearAll(lightmapdict_t *lightmaps)
* otherwise emit a warning. * otherwise emit a warning.
*/ */
static void Lightmap_Save( 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) { if (lightmap->style == INVALID_LIGHTSTYLE) {
lightmap->style = style; lightmap->style = style;
} }
@ -1294,7 +1300,7 @@ static void LightFace_Entity(
sample.color += rs.getPushedRayColor(j); sample.color += rs.getPushedRayColor(j);
sample.direction += rs.getPushedRayNormalContrib(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 * 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 settings::worldspawn_keys &cfg = *lightsurf->cfg;
const modelinfo_t *modelinfo = lightsurf->modelinfo; 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); sample.direction += rs.getPushedRayNormalContrib(j);
total_light_ray_hits++; 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) { 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) { 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 // 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 * 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; const settings::worldspawn_keys &cfg = *lightsurf->cfg;
/* use a style 0 light map */ /* use a style 0 light map */
@ -1846,7 +1852,7 @@ static void LightFace_DirtDebug(const lightsurf_t *lightsurf, lightmapdict_t *li
sample.color = {light}; 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 * 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 */ /* use a style 0 light map */
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, 0, lightsurf); 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 */ /* use a style 0 light map */
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, 0, lightsurf); 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)); 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] // 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 surface light contributed anything, save.
if (hit) 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<uint8_t> *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); 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; 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); 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; 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 */ /* Dirtmapping borrowed from q3map2, originally by RaP7oR */
@ -2828,28 +2834,34 @@ static std::vector<qvec4f> BoxBlurImage(const std::vector<qvec4f> &input, int w,
return res; return res;
} }
// check if the given face can actually store luxel data
bool Face_IsLightmapped(const mbsp_t *bsp, const mface_t *face) bool Face_IsLightmapped(const mbsp_t *bsp, const mface_t *face)
{ {
const mtexinfo_t *texinfo = Face_Texinfo(bsp, face); const mtexinfo_t *texinfo = Face_Texinfo(bsp, face);
if (texinfo == nullptr) if (texinfo == nullptr) {
return false; 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. const char *texname = Face_TextureName(bsp, face);
// 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;
}*/
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); const char *texname = Face_TextureName(bsp, face);
Q_assert(Face_IsLightmapped(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++) { for (int mapnum = 0; mapnum < numstyles; mapnum++) {
@ -3287,18 +3297,10 @@ std::unique_ptr<lightsurf_t> CreateLightmapSurface(const mbsp_t *bsp, const mfac
if (face->numedges < 3) if (face->numedges < 3)
return nullptr; return nullptr;
if (!Face_IsLightmapped(bsp, face)) // if we don't have a lightmap or emissive, we're done
return nullptr; if (!Face_IsEmissive(bsp, face) && !Face_IsLightmapped(bsp, face)) {
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"))
return nullptr; return nullptr;
}
return Lightsurf_Init(modelinfo, cfg, face, bsp, facesup, facesup_decoupled); 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()) for (const sun_t &sun : GetSuns())
if (sun.sunlight > 0) if (sun.sunlight > 0)
LightFace_Sky(&sun, &lightsurf, lightmaps); LightFace_Sky(bsp, &sun, &lightsurf, lightmaps);
// mxd. Add surface lights... // mxd. Add surface lights...
// FIXME: negative 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 */ /* replace lightmaps with AO for debugging */
if (light_options.debugmode == debugmodes::dirt) if (light_options.debugmode == debugmodes::dirt)
LightFace_DirtDebug(&lightsurf, lightmaps); LightFace_DirtDebug(bsp, &lightsurf, lightmaps);
if (light_options.debugmode == debugmodes::phong) if (light_options.debugmode == debugmodes::phong)
LightFace_PhongDebug(&lightsurf, lightmaps); LightFace_PhongDebug(bsp, &lightsurf, lightmaps);
if (light_options.debugmode == debugmodes::debugoccluded) if (light_options.debugmode == debugmodes::debugoccluded)
LightFace_OccludedDebug(&lightsurf, lightmaps); LightFace_OccludedDebug(bsp, &lightsurf, lightmaps);
if (light_options.debugmode == debugmodes::debugneighbours) 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()) for (const sun_t &sun : GetSuns())
if (sun.sunlight < 0) if (sun.sunlight < 0)
LightFace_Sky(&sun, &lightsurf, lightmaps); LightFace_Sky(bsp, &sun, &lightsurf, lightmaps);
} }
} }
if (light_options.debugmode == debugmodes::mottle) if (light_options.debugmode == debugmodes::mottle)
LightFace_DebugMottle(&lightsurf, lightmaps); LightFace_DebugMottle(bsp, &lightsurf, lightmaps);
} }
// lightgrid // lightgrid

View File

@ -57,7 +57,7 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys
{ {
auto &surf_ptr = LightSurfaces()[face - bsp->dfaces.data()]; auto &surf_ptr = LightSurfaces()[face - bsp->dfaces.data()];
if (!surf_ptr) { if (!surf_ptr || !Face_IsEmissive(bsp, face)) {
return; return;
} }