cherry pick commit 96cd23761c from @Shpoike

Removed legacy switchable lightstyles limit (requires updated engines when exceeded). Added -facestyles argument that allows for >4 styles per face, as well as potentially increasing style indexes to 16bit for far far more switchable styles.
This commit is contained in:
Jonathan 2022-06-21 15:35:39 -04:00
parent 827d382d5a
commit 210d994445
7 changed files with 110 additions and 31 deletions

View File

@ -399,6 +399,7 @@ struct mtexinfo_t
};
constexpr size_t MAXLIGHTMAPS = 4;
constexpr uint16_t INVALID_LIGHTSTYLE_OLD = 0xffu;
struct mface_t
{

View File

@ -76,7 +76,7 @@ public:
{{"linear", LF_LINEAR}, {"inverse", LF_INVERSE}, {"inverse2", LF_INVERSE2}, {"infinite", LF_INFINITE}, {"localmin", LF_LOCALMIN}, {"inverse2a", LF_INVERSE2A}}};
settings::setting_scalar spotangle{this, "angle", 40.0};
settings::setting_scalar spotangle2{this, "softangle", 0.0};
settings::setting_numeric<int32_t> style{this, "style", 0, 0, 254};
settings::setting_numeric<int32_t> style{this, "style", 0, 0, INVALID_LIGHTSTYLE - 1};
settings::setting_scalar anglescale{this, {"anglesense", "anglescale"}, -1.0}; // fallback to worldspawn
settings::setting_scalar dirtscale{this, "dirtscale", 0.0};
settings::setting_scalar dirtgain{this, "dirtgain", 0};

View File

@ -450,6 +450,7 @@ public:
&experimental_group, "writes both rgb and directions data into the bsp itself"};
setting_bool litonly{this, "litonly", false, &output_group, "only write .lit file, don't modify BSP"};
setting_bool nolights{this, "nolights", false, &output_group, "ignore light entities (only sunlight/minlight)"};
setting_int32 facestyles{this, "facestyles", 4, &output_group, "max amount of styles per face; requires BSPX lump"};
inline void CheckNoDebugModeSet()
{

View File

@ -41,13 +41,16 @@ struct litheader_t
} v2;
};
constexpr size_t MAXLIGHTMAPSSUP = 16;
constexpr uint16_t INVALID_LIGHTSTYLE = 0xffffu;
/* internal representation for bspx/lit2 */
struct facesup_t
{
float lmscale;
uint8_t styles[MAXLIGHTMAPS]; /* scaled styles */
uint16_t styles[MAXLIGHTMAPSSUP]; /* scaled styles */
int32_t lightofs; /* scaled lighting */
unsigned short extent[2];
uint16_t extent[2];
};
void WriteLitFile(const mbsp_t *bsp, facesup_t *facesup, const fs::path &filename, int version);

View File

@ -168,6 +168,11 @@ void light_settings::postinitialize(int argc, const char **argv)
}
}
// upgrade to uint16 if facestyles is specified
if (options.facestyles.value() > MAXLIGHTMAPS && !options.compilerstyle_max.isChanged()) {
options.compilerstyle_max.setValue(INVALID_LIGHTSTYLE);
}
common_settings::postinitialize(argc, argv);
}
} // namespace settings
@ -318,13 +323,13 @@ static void LightThread(const mbsp_t *bsp, size_t facenum)
LightFace(bsp, f, nullptr, options);
else if (options.novanilla.value()) {
f->lightofs = -1;
f->styles[0] = 255;
f->styles[0] = INVALID_LIGHTSTYLE_OLD;
LightFace(bsp, f, faces_sup + facenum, options);
} else if (faces_sup[facenum].lmscale == face_modelinfo->lightmapscale) {
LightFace(bsp, f, nullptr, options);
faces_sup[facenum].lightofs = f->lightofs;
LightFace(bsp, f, faces_sup + facenum, options);
f->lightofs = faces_sup[facenum].lightofs;
for (int i = 0; i < MAXLIGHTMAPS; i++)
faces_sup[facenum].styles[i] = f->styles[i];
f->styles[i] = faces_sup[facenum].styles[i];
} else {
LightFace(bsp, f, nullptr, options);
LightFace(bsp, f, faces_sup + facenum, options);
@ -449,7 +454,7 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
auto lmshift_lump = bspdata->bspx.entries.find("LMSHIFT");
if (lmshift_lump == bspdata->bspx.entries.end() && options.write_litfile != lightfile::lit2)
if (lmshift_lump == bspdata->bspx.entries.end() && options.write_litfile != lightfile::lit2 && options.facestyles.value() <= 4)
faces_sup = nullptr; // no scales, no lit2
else { // we have scales or lit2 output. yay...
faces_sup = new facesup_t[bsp.dfaces.size()]{};
@ -518,23 +523,79 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
logging::print("lightdatasize: {}\n", bsp.dlightdata.size());
// kill this stuff if its somehow found.
bspdata->bspx.entries.erase("LMSTYLE16");
bspdata->bspx.entries.erase("LMSTYLE");
bspdata->bspx.entries.erase("LMOFFSET");
if (faces_sup) {
std::vector<uint8_t> styles(4 * bsp.dfaces.size());
bool needoffsets = false;
bool needstyles = false;
int maxstyle = 0;
int stylesperface = 0;
for (int i = 0; i < bsp.dfaces.size(); i++) {
if (bsp.dfaces[i].lightofs != faces_sup[i].lightofs)
needoffsets = true;
int j = 0;
for (; j < MAXLIGHTMAPSSUP; j++) {
if (faces_sup[i].styles[j] == INVALID_LIGHTSTYLE)
break;
if (bsp.dfaces[i].styles[j] != faces_sup[i].styles[j])
needstyles = true;
if (maxstyle < faces_sup[i].styles[j])
maxstyle = faces_sup[i].styles[j];
}
if (stylesperface < j)
stylesperface = j;
}
needstyles |= (stylesperface>4);
logging::print("max {} styles per face{}\n", stylesperface, maxstyle >= INVALID_LIGHTSTYLE_OLD ? ", 16bit lightstyles" : "");
if (needstyles) {
if (maxstyle >= INVALID_LIGHTSTYLE_OLD) {
/*needs bigger datatype*/
std::vector<uint8_t> styles_mem(sizeof(uint16_t) * stylesperface * bsp.dfaces.size());
omemstream styles(styles_mem.data(), std::ios_base::out | std::ios_base::binary);
styles << endianness<std::endian::little>;
for (size_t i = 0; i < bsp.dfaces.size(); i++) {
for (size_t j = 0; j < stylesperface; j++) {
styles <= faces_sup[i].styles[j];
}
}
bspdata->bspx.transfer("LMSTYLE16", styles_mem);
} else {
/*original LMSTYLE lump was just for different lmshift info*/
std::vector<uint8_t> styles_mem(stylesperface * bsp.dfaces.size());
for (size_t i = 0, k = 0; i < bsp.dfaces.size(); i++) {
for (size_t j = 0; j < stylesperface; j++, k++) {
styles_mem[k] = faces_sup[i].styles[j];
}
}
bspdata->bspx.transfer("LMSTYLE", styles_mem);
}
}
if (needoffsets) {
std::vector<uint8_t> offsets_mem(bsp.dfaces.size() * sizeof(int32_t));
omemstream offsets(offsets_mem.data(), std::ios_base::out | std::ios_base::binary);
offsets << endianness<std::endian::little>;
for (int i = 0; i < bsp.dfaces.size(); i++) {
for (size_t i = 0; i < bsp.dfaces.size(); i++) {
offsets <= faces_sup[i].lightofs;
for (int j = 0; j < MAXLIGHTMAPS; j++)
styles[i * 4 + j] = faces_sup[i].styles[j];
}
bspdata->bspx.transfer("LMSTYLE", styles);
bspdata->bspx.transfer("LMOFFSET", offsets_mem);
}
}
}
static void LoadExtendedTexinfoFlags(const fs::path &sourcefilename, const mbsp_t *bsp)
{

View File

@ -1014,7 +1014,7 @@ static lightmap_t *Lightmap_ForStyle(lightmapdict_t *lightmaps, const int style,
// no exact match, check for an unsaved one
for (auto &lm : *lightmaps) {
if (lm.style == 255) {
if (lm.style == INVALID_LIGHTSTYLE) {
Lightmap_AllocOrClear(&lm, lightsurf);
return &lm;
}
@ -1022,7 +1022,7 @@ static lightmap_t *Lightmap_ForStyle(lightmapdict_t *lightmaps, const int style,
// add a new one to the vector (invalidates existing lightmap_t pointers)
lightmap_t &newLightmap = lightmaps->emplace_back();
newLightmap.style = 255;
newLightmap.style = INVALID_LIGHTSTYLE;
Lightmap_AllocOrClear(&newLightmap, lightsurf);
return &newLightmap;
}
@ -1030,7 +1030,7 @@ static lightmap_t *Lightmap_ForStyle(lightmapdict_t *lightmaps, const int style,
static void Lightmap_ClearAll(lightmapdict_t *lightmaps)
{
for (auto &lm : *lightmaps) {
lm.style = 255;
lm.style = INVALID_LIGHTSTYLE;
}
}
@ -1043,7 +1043,7 @@ static void Lightmap_ClearAll(lightmapdict_t *lightmaps)
static void Lightmap_Save(
lightmapdict_t *lightmaps, const lightsurf_t *lightsurf, lightmap_t *lightmap, const int style)
{
if (lightmap->style == 255) {
if (lightmap->style == INVALID_LIGHTSTYLE) {
lightmap->style = style;
}
}
@ -3151,13 +3151,26 @@ static void WriteLightmaps(
return;
}
int maxfstyles = facesup ? MAXLIGHTMAPSSUP : MAXLIGHTMAPS;
if (maxfstyles > options.facestyles.value()) {
maxfstyles = options.facestyles.value(); //truncate it a little
}
int maxstyle = facesup ? INVALID_LIGHTSTYLE : INVALID_LIGHTSTYLE_OLD;
// intermediate collection for sorting lightmaps
std::vector<std::pair<float, const lightmap_t *>> sortable;
for (const lightmap_t &lightmap : *lightmaps) {
// skip un-saved lightmaps
if (lightmap.style == 255)
if (lightmap.style == INVALID_LIGHTSTYLE)
continue;
if (lightmap.style > maxstyle) {
logging::print("WARNING: Style {} too high\n"
" lightmap point near {}\n",
lightmap.style,
lightsurf->points[0]);
continue;
}
// skip lightmaps where all samples have brightness below 1
if (bsp->loadversion->game->id != GAME_QUAKE_II) { // HACK: don't do this on Q2. seems if all styles are 0xff,
@ -3177,7 +3190,7 @@ static void WriteLightmaps(
std::vector<const lightmap_t *> sorted;
for (const auto &pair : sortable) {
if (sorted.size() == MAXLIGHTMAPS) {
if (sorted.size() == maxfstyles) {
logging::print("WARNING: Too many light styles on a face\n"
" lightmap point near [{}]\n",
lightsurf->points[0]);
@ -3189,7 +3202,7 @@ static void WriteLightmaps(
/* final number of lightmaps */
const int numstyles = static_cast<int>(sorted.size());
Q_assert(numstyles <= MAXLIGHTMAPS);
Q_assert(numstyles <= MAXLIGHTMAPSSUP);
/* update face info (either core data or supplementary stuff) */
if (facesup) {
@ -3199,8 +3212,8 @@ static void WriteLightmaps(
for (mapnum = 0; mapnum < numstyles; mapnum++) {
facesup->styles[mapnum] = sorted.at(mapnum)->style;
}
for (; mapnum < MAXLIGHTMAPS; mapnum++) {
facesup->styles[mapnum] = 255;
for (; mapnum < MAXLIGHTMAPSSUP; mapnum++) {
facesup->styles[mapnum] = INVALID_LIGHTSTYLE;
}
facesup->lmscale = lightsurf->lightmapscale;
} else {
@ -3209,7 +3222,7 @@ static void WriteLightmaps(
face->styles[mapnum] = sorted.at(mapnum)->style;
}
for (; mapnum < MAXLIGHTMAPS; mapnum++) {
face->styles[mapnum] = 255;
face->styles[mapnum] = INVALID_LIGHTSTYLE_OLD;
}
}
@ -3376,12 +3389,12 @@ void LightFace(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, const setti
/* some surfaces don't need lightmaps */
if (facesup) {
facesup->lightofs = -1;
for (int i = 0; i < MAXLIGHTMAPS; i++)
facesup->styles[i] = 255;
for (int i = 0; i < MAXLIGHTMAPSSUP; i++)
facesup->styles[i] = INVALID_LIGHTSTYLE;
} else {
face->lightofs = -1;
for (int i = 0; i < MAXLIGHTMAPS; i++)
face->styles[i] = 255;
face->styles[i] = INVALID_LIGHTSTYLE_OLD;
}
}

View File

@ -86,7 +86,7 @@ static void MakeSurfaceLightsThread(const mbsp_t *bsp, const settings::worldspaw
style = surflight->epairs->get_int("style");
if (surflight->color.isChanged()) {
texture_color = surflight->color.value();
texture_color = surflight->color.value() / 255.f;
}
break;
}