diff --git a/include/light/light.hh b/include/light/light.hh index 1ffa9de6..6cbf0e4a 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -400,6 +400,7 @@ extern uint8_t *filebase; extern uint8_t *lit_filebase; extern uint8_t *lux_filebase; +extern int facestyles; extern int oversample; extern int write_litfile; extern int write_luxfile; diff --git a/include/light/litfile.hh b/include/light/litfile.hh index 1fe76133..a086049b 100644 --- a/include/light/litfile.hh +++ b/include/light/litfile.hh @@ -36,10 +36,13 @@ typedef struct litheader_s { } litheader_t; /* internal representation for bspx/lit2 */ +#define MAXLIGHTMAPSSUP 16 +#define INVALID_LIGHTSTYLE 0xffffu +#define INVALID_LIGHTSTYLE_OLD 0xffu typedef struct { float lmscale; - uint8_t styles[MAXLIGHTMAPS]; /* scaled styles */ - int32_t lightofs; /* scaled lighting */ + uint16_t styles[MAXLIGHTMAPSSUP]; /* scaled styles */ + int32_t lightofs; /* scaled lighting */ unsigned short extent[2]; } facesup_t; diff --git a/include/qbsp/bspfile.hh b/include/qbsp/bspfile.hh index 145e01d5..16cbd818 100644 --- a/include/qbsp/bspfile.hh +++ b/include/qbsp/bspfile.hh @@ -172,7 +172,8 @@ typedef struct { uint32_t v[2]; /* vertex numbers */ } bsp2_dedge_t; -#define MAXLIGHTMAPS 4 +#define MAXLIGHTMAPS 4 +#define INVALID_LIGHTSTYLE_OLD 0xffu /*signifies 'no more lightstyles'*/ typedef struct { int16_t planenum; int16_t side; diff --git a/light/entities.cc b/light/entities.cc index be2fd378..113b676f 100644 --- a/light/entities.cc +++ b/light/entities.cc @@ -61,7 +61,6 @@ const char * light_t::classname() const { static std::vector> lightstyleForTargetname; -#define MAX_SWITCHABLE_STYLES 64 static entdict_t &WorldEnt() { @@ -99,12 +98,13 @@ LightStyleForTargetname(const globalconfig_t& cfg, const std::string &targetname // generate a new style number and return it const int newStylenum = cfg.compilerstyle_start.intValue() + lightstyleForTargetname.size(); - - // check if full - if (newStylenum >= MAX_SWITCHABLE_STYLES) { - Error("%s: Too many unique light targetnames (max=%d)\n", __func__, MAX_SWITCHABLE_STYLES); + if (newStylenum >= (facestyles?INVALID_LIGHTSTYLE:INVALID_LIGHTSTYLE_OLD)) + { + if (!facestyles) + Error("%s: Too many unique light targetnames (reached max of %i)\nTip: Use '-facestyles N' for 16bit lightstyle limits in supporting engines.", __func__, newStylenum-cfg.compilerstyle_start.intValue()); + else + Error("%s: Too many unique light targetnames (reached max of %i)\n", __func__, newStylenum-cfg.compilerstyle_start.intValue()); } - lightstyleForTargetname.emplace_back(targetname, newStylenum); //mxd. https://clang.llvm.org/extra/clang-tidy/checks/modernize-use-emplace.html if (verbose_log) { @@ -375,8 +375,8 @@ CheckEntityFields(const globalconfig_t &cfg, light_t *entity) entity->light.setFloatValue(entity->light.floatValue() / entity->samples.intValue()); } - if (entity->style.intValue() < 0 || entity->style.intValue() > 254) { - Error("Bad light style %i (must be 0-254)", entity->style.intValue()); + if (entity->style.intValue() < 0 || entity->style.intValue() > INVALID_LIGHTSTYLE) { + Error("Bad light style %i (must be 0-%i)", entity->style.intValue(), INVALID_LIGHTSTYLE-1); } } @@ -1272,9 +1272,8 @@ WriteEntitiesToString(const globalconfig_t& cfg, mbsp_t *bsp) free(bsp->dentdata); /* FIXME - why are we printing this here? */ - logprint("%i switchable light styles (%d max)\n", - static_cast(lightstyleForTargetname.size()), - MAX_SWITCHABLE_STYLES - cfg.compilerstyle_start.intValue()); + logprint("%i switchable light styles\n", + static_cast(lightstyleForTargetname.size())); bsp->entdatasize = entdata.size() + 1; // +1 for a null byte at the end bsp->dentdata = (char *) calloc(bsp->entdatasize, 1); diff --git a/light/light.cc b/light/light.cc index 2851c2b2..094c5c44 100644 --- a/light/light.cc +++ b/light/light.cc @@ -94,6 +94,7 @@ std::vector selfshadowlist; std::vector shadowworldonlylist; std::vector switchableshadowlist; +int facestyles = 0; //max styles per face - uses bspx stuff. int oversample = 1; int write_litfile = 0; /* 0 for none, 1 for .lit, 2 for bspx, 3 for both */ int write_luxfile = 0; /* 0 for none, 1 for .lux, 2 for bspx, 3 for both */ @@ -281,15 +282,15 @@ LightThread(void *arg) else if (scaledonly) { f->lightofs = -1; - f->styles[0] = 255; + f->styles[0] = INVALID_LIGHTSTYLE_OLD; LightFace(bsp, f, faces_sup + facenum, cfg_static); } else if (faces_sup[facenum].lmscale == face_modelinfo->lightmapscale) { - LightFace(bsp, f, nullptr, cfg_static); - faces_sup[facenum].lightofs = f->lightofs; + LightFace(bsp, f, faces_sup + facenum, cfg_static); + 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 { @@ -418,10 +419,8 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale) BSPX_AddLump(bspdata, "LMSHIFT", NULL, 0); const unsigned char *lmshift_lump = (const unsigned char *)BSPX_GetLump(bspdata, "LMSHIFT", NULL); - if (!lmshift_lump && write_litfile != ~0) - faces_sup = NULL; //no scales, no lit2 - else - { //we have scales or lit2 output. yay... + if (lmshift_lump || (write_litfile&2) || (write_luxfile&2) || facestyles) + { //we have scales/bspx/lit2 output. yay... faces_sup = (facesup_t *)malloc(sizeof(*faces_sup) * bsp->numfaces); memset(faces_sup, 0, sizeof(*faces_sup) * bsp->numfaces); if (lmshift_lump) @@ -435,6 +434,10 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale) faces_sup[i].lmscale = modelinfo.at(0)->lightmapscale; } } + else + faces_sup = NULL; //no scales, no lit2, no -bspx + if (!facestyles) + facestyles = 4; CalcualateVertexNormals(bsp); @@ -484,20 +487,69 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale) } logprint("lightdatasize: %i\n", bsp->lightdatasize); - if (faces_sup) { - uint8_t *styles = (uint8_t *)malloc(sizeof(*styles)*4*bsp->numfaces); - int32_t *offsets = (int32_t *)malloc(sizeof(*offsets)*bsp->numfaces); + //kill this stuff if it lingered from a previous light compile + BSPX_AddLump(bspdata, "LMSTYLE16", NULL, 0); + BSPX_AddLump(bspdata, "LMSTYLE", NULL, 0); + BSPX_AddLump(bspdata, "LMOFFSET", NULL, 0); + + //write out new stuff if we have it. + if (faces_sup) + { + bool needoffsets = false; + bool needstyles = false; + int maxstyle = 0; + int stylesperface = 0; + for (int i = 0; i < bsp->numfaces; i++) { - offsets[i] = faces_sup[i].lightofs; - for (int j = 0; j < MAXLIGHTMAPS; j++) - styles[i*4+j] = faces_sup[i].styles[j]; + 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); + + logprint("max %i styles per face%s\n", stylesperface, maxstyle >= INVALID_LIGHTSTYLE_OLD?", 16bit lightstyles":""); + + if (needstyles) + { + if (maxstyle >= INVALID_LIGHTSTYLE_OLD/*needs bigger datatype*/) { + /*LMSTYLE16 lump provides for more than 4 styles per surface, as well as more than 255 styles*/ + uint16_t *styles = (uint16_t *)malloc(sizeof(*styles)*stylesperface*bsp->numfaces); + for (int i = 0; i < bsp->numfaces; i++) { + for (int j = 0; j < stylesperface; j++) + styles[i*stylesperface+j] = faces_sup[i].styles[j]; + } + BSPX_AddLump(bspdata, "LMSTYLE16", styles, sizeof(*styles)*stylesperface*bsp->numfaces); + } + else { + /*original LMSTYLE lump was just for different lmshift info*/ + if (stylesperface < 4) + stylesperface = 4; /*better compat*/ + uint8_t *styles = (uint8_t *)malloc(sizeof(*styles)*stylesperface*bsp->numfaces); + for (int i = 0; i < bsp->numfaces; i++) { + for (int j = 0; j < stylesperface; j++) + styles[i*stylesperface+j] = faces_sup[i].styles[j]; + } + BSPX_AddLump(bspdata, "LMSTYLE", styles, sizeof(*styles)*stylesperface*bsp->numfaces); + } + } + if (needoffsets) + { + int32_t *offsets = (int32_t *)malloc(sizeof(*offsets)*bsp->numfaces); + for (int i = 0; i < bsp->numfaces; i++) { + offsets[i] = faces_sup[i].lightofs; + } + BSPX_AddLump(bspdata, "LMOFFSET", offsets, sizeof(*offsets)*bsp->numfaces); } - BSPX_AddLump(bspdata, "LMSTYLE", styles, sizeof(*styles)*4*bsp->numfaces); - BSPX_AddLump(bspdata, "LMOFFSET", offsets, sizeof(*offsets)*bsp->numfaces); - } else { - //kill this stuff if its somehow found. - BSPX_AddLump(bspdata, "LMSTYLE", NULL, 0); - BSPX_AddLump(bspdata, "LMOFFSET", NULL, 0); } } @@ -810,7 +862,8 @@ static void PrintUsage() " -bspxlit writes rgb data into the bsp itself\n" " -bspx writes both rgb and directions data into the bsp itself\n" " -novanilla implies -bspxlit. don't write vanilla lighting\n" -" -radlights filename.rad loads a file\n"); +" -radlights filename.rad loads a file\n" +" -facestyles n (bspx) overrides the max number of lightstyles per face\n"); printf("\n"); printf("Overridable worldspawn keys:\n"); @@ -997,6 +1050,11 @@ light_main(int argc, const char **argv) } else if (!strcmp(argv[i], "-bspx")) { write_litfile |= 2; write_luxfile |= 2; + } else if (!strcmp(argv[i], "-facestyles")) { + if ((i + 1) < argc && isdigit(argv[i + 1][0])) + facestyles = atoi(argv[++i]); + else + facestyles = 0; } else if (!strcmp(argv[i], "-novanilla")) { scaledonly = true; } else if ( !strcmp( argv[ i ], "-radlights" ) ) { diff --git a/light/ltface.cc b/light/ltface.cc index 6c964877..9e0e5ff3 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -900,7 +900,7 @@ Lightmap_ForStyle(lightmapdict_t *lightmaps, const int style, const lightsurf_t // 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; } @@ -908,7 +908,7 @@ Lightmap_ForStyle(lightmapdict_t *lightmaps, const int style, const lightsurf_t // add a new one to the vector (invalidates existing lightmap_t pointers) lightmap_t newLightmap {}; - newLightmap.style = 255; + newLightmap.style = INVALID_LIGHTSTYLE; Lightmap_AllocOrClear(&newLightmap, lightsurf); lightmaps->push_back(newLightmap); @@ -919,7 +919,7 @@ static void Lightmap_ClearAll(lightmapdict_t *lightmaps) { for (auto &lm : *lightmaps) { - lm.style = 255; + lm.style = INVALID_LIGHTSTYLE; } } @@ -933,7 +933,7 @@ 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; } } @@ -3072,13 +3072,25 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const return; } + int maxfstyles = facesup?MAXLIGHTMAPSSUP:MAXLIGHTMAPS; + if (maxfstyles > facestyles) + maxfstyles = facestyles; //truncate it a little + int maxstyle = facesup?INVALID_LIGHTSTYLE:INVALID_LIGHTSTYLE_OLD; + // intermediate collection for sorting lightmaps std::vector> 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) { + logprint("WARNING: Style %i too high\n" + " lightmap point near (%s)\n", + lightmap.style, + VecStr(lightsurf->points[0]).c_str()); + continue; + } // skip lightmaps where all samples have brightness below 1 if (bsp->loadversion != Q2_BSPVERSION) { // HACK: don't do this on Q2. seems if all styles are 0xff, the face is drawn fullbright instead of black (Q1) @@ -3097,7 +3109,7 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const std::vector sorted; for (const auto &pair : sortable) { - if (sorted.size() == MAXLIGHTMAPS) { + if (sorted.size() == maxfstyles) { logprint("WARNING: Too many light styles on a face\n" " lightmap point near (%s)\n", VecStr(lightsurf->points[0]).c_str()); @@ -3109,7 +3121,7 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const /* final number of lightmaps */ const int numstyles = static_cast(sorted.size()); - Q_assert(numstyles <= MAXLIGHTMAPS); + Q_assert(numstyles <= MAXLIGHTMAPSSUP); /* update face info (either core data or supplementary stuff) */ if (facesup) @@ -3120,8 +3132,8 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const 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; } @@ -3132,7 +3144,7 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const face->styles[mapnum] = sorted.at(mapnum)->style; } for (; mapnum < MAXLIGHTMAPS; mapnum++) { - face->styles[mapnum] = 255; + face->styles[mapnum] = INVALID_LIGHTSTYLE_OLD; } } @@ -3297,14 +3309,14 @@ LightFace(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const globa 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; } }