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;
}
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

View File

@ -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;
/**

View File

@ -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;

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,
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);

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,
const qvec3d &facenormal, const qvec3d &facemidpoint)
{
if (!Face_IsEmissive(bsp, surf.face)) {
return;
}
bouncelightpoints += points.size();
// 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) {
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<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__)
_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<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__)
_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<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__)
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
#endif

View File

@ -589,150 +589,154 @@ static std::unique_ptr<lightsurf_t> 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<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);
@ -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<qvec4f> BoxBlurImage(const std::vector<qvec4f> &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<lightsurf_t> 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

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()];
if (!surf_ptr) {
if (!surf_ptr || !Face_IsEmissive(bsp, face)) {
return;
}