light: add -litonly option for re-lighting a bsp without modifying it

This commit is contained in:
Eric Wasylishen 2020-08-03 00:20:45 -06:00
parent 189a83051a
commit 03ed0697a4
3 changed files with 183 additions and 76 deletions

View File

@ -401,6 +401,7 @@ extern qboolean scaledonly;
extern uint64_t *extended_texinfo_flags; extern uint64_t *extended_texinfo_flags;
extern qboolean novisapprox; extern qboolean novisapprox;
extern bool nolights; extern bool nolights;
extern bool litonly;
typedef enum { typedef enum {
backend_bsp, backend_bsp,
@ -417,6 +418,7 @@ lockable_setting_t *FindSetting(std::string name);
void SetGlobalSetting(std::string name, std::string value, bool cmdline); void SetGlobalSetting(std::string name, std::string value, bool cmdline);
void FixupGlobalSettings(void); void FixupGlobalSettings(void);
void GetFileSpace(byte **lightdata, byte **colordata, byte **deluxdata, int size); void GetFileSpace(byte **lightdata, byte **colordata, byte **deluxdata, int size);
void GetFileSpace_PreserveOffsetInBsp(byte **lightdata, byte **colordata, byte **deluxdata, int lightofs);
const modelinfo_t *ModelInfoForModel(const mbsp_t *bsp, int modelnum); const modelinfo_t *ModelInfoForModel(const mbsp_t *bsp, int modelnum);
const modelinfo_t *ModelInfoForFace(const mbsp_t *bsp, int facenum); const modelinfo_t *ModelInfoForFace(const mbsp_t *bsp, int facenum);
//bool Leaf_HasSky(const mbsp_t *bsp, const mleaf_t *leaf); //mxd. Missing definition //bool Leaf_HasSky(const mbsp_t *bsp, const mleaf_t *leaf); //mxd. Missing definition

View File

@ -67,18 +67,26 @@ qboolean surflight_dump = false;
static facesup_t *faces_sup; //lit2/bspx stuff static facesup_t *faces_sup; //lit2/bspx stuff
byte *filebase; // start of lightmap data /// start of lightmap data
static byte *file_p; // start of free space after data byte *filebase;
static byte *file_end; // end of free space for lightmap data /// offset of start of free space after data (should be kept a multiple of 4)
static int file_p;
/// offset of end of free space for lightmap data
static int file_end;
byte *lit_filebase; // start of litfile data /// start of litfile data
static byte *lit_file_p; // start of free space after litfile data byte *lit_filebase;
static byte *lit_file_end; // end of space for litfile data /// offset of start of free space after litfile data (should be kept a multiple of 12)
static int lit_file_p;
/// offset of end of space for litfile data
static int lit_file_end;
byte *lux_buffer; // luxfile allocation (misaligned) /// start of luxfile data
byte *lux_filebase; // start of luxfile data byte *lux_filebase;
static byte *lux_file_p; // start of free space after luxfile data /// offset of start of free space after luxfile data (should be kept a multiple of 12)
static byte *lux_file_end; // end of space for luxfile data static int lux_file_p;
/// offset of end of space for luxfile data
static int lux_file_end;
std::vector<modelinfo_t *> modelinfo; std::vector<modelinfo_t *> modelinfo;
std::vector<const modelinfo_t *> tracelist; std::vector<const modelinfo_t *> tracelist;
@ -96,6 +104,7 @@ backend_t rtbackend = backend_embree;
bool debug_highlightseams = false; bool debug_highlightseams = false;
debugmode_t debugmode = debugmode_none; debugmode_t debugmode = debugmode_none;
bool verbose_log = false; bool verbose_log = false;
bool litonly = false;
uint64_t *extended_texinfo_flags = NULL; uint64_t *extended_texinfo_flags = NULL;
@ -172,26 +181,20 @@ GetFileSpace(byte **lightdata, byte **colordata, byte **deluxdata, int size)
{ {
ThreadLock(); ThreadLock();
/* align to 4 byte boudaries */ *lightdata = filebase + file_p;
file_p = (byte *)(((uintptr_t)file_p + 3) & ~3); *colordata = lit_filebase + lit_file_p;
*lightdata = file_p; *deluxdata = lux_filebase + lux_file_p;
// if size isn't a multiple of 4, round up to the next multiple of 4
if ((size % 4) != 0) {
size += (4 - (size % 4));
}
// increment the next writing offsets, aligning them to 4 byte boundaries (file_p)
// and 12-byte boundaries (lit_file_p/lux_file_p)
file_p += size; file_p += size;
lit_file_p += 3 * size;
if (colordata) { lux_file_p += 3 * size;
/* align to 12 byte boundaries to match offets with 3 * lightdata */
if ((uintptr_t)lit_file_p % 12)
lit_file_p += 12 - ((uintptr_t)lit_file_p % 12);
*colordata = lit_file_p;
lit_file_p += size * 3;
}
if (deluxdata) {
/* align to 12 byte boundaries to match offets with 3 * lightdata */
if ((uintptr_t)lux_file_p % 12)
lux_file_p += 12 - ((uintptr_t)lux_file_p % 12);
*deluxdata = lux_file_p;
lux_file_p += size * 3;
}
ThreadUnlock(); ThreadUnlock();
@ -202,6 +205,26 @@ GetFileSpace(byte **lightdata, byte **colordata, byte **deluxdata, int size)
Error("%s: overrun", __func__); Error("%s: overrun", __func__);
} }
/**
* Special version of GetFileSpace for when we're relighting a .bsp and can't modify it.
* In this case the offsets are already known.
*/
void GetFileSpace_PreserveOffsetInBsp(byte **lightdata, byte **colordata, byte **deluxdata, int lightofs) {
Q_assert(lightofs >= 0);
*lightdata = filebase + lightofs;
if (colordata) {
*colordata = lit_filebase + (lightofs * 3);
}
if (deluxdata) {
*deluxdata = lux_filebase + (lightofs * 3);
}
// NOTE: file_p et. al. are not updated, since we're not dynamically allocating the lightmaps
}
const modelinfo_t *ModelInfoForModel(const mbsp_t *bsp, int modelnum) const modelinfo_t *ModelInfoForModel(const mbsp_t *bsp, int modelnum)
{ {
return modelinfo.at(modelnum); return modelinfo.at(modelnum);
@ -362,35 +385,30 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale)
logprint("--- LightWorld ---\n" ); logprint("--- LightWorld ---\n" );
mbsp_t *const bsp = &bspdata->data.mbsp; mbsp_t *const bsp = &bspdata->data.mbsp;
if (bsp->dlightdata) free(filebase);
free(bsp->dlightdata); free(lit_filebase);
if (lux_buffer) free(lux_filebase);
free(lux_buffer);
/* FIXME - remove this limit */ /* greyscale data stored in a separate buffer */
bsp->lightdatasize = MAX_MAP_LIGHTING; filebase = (byte *)calloc(MAX_MAP_LIGHTING, 1);
bsp->dlightdata = (byte *)malloc(bsp->lightdatasize + 16); /* for alignment */ if (!filebase)
if (!bsp->dlightdata) Error("%s: allocation of %i bytes failed.", __func__, MAX_MAP_LIGHTING);
Error("%s: allocation of %i bytes failed.", file_p = 0;
__func__, bsp->lightdatasize); file_end = MAX_MAP_LIGHTING;
memset(bsp->dlightdata, 0, bsp->lightdatasize + 16);
bsp->lightdatasize /= 4;
/* align filebase to a 4 byte boundary */ /* litfile data stored in a separate buffer */
filebase = file_p = (byte *)(((uintptr_t)bsp->dlightdata + 3) & ~3); lit_filebase = (byte *)calloc(MAX_MAP_LIGHTING*3, 1);
file_end = filebase + bsp->lightdatasize; if (!lit_filebase)
Error("%s: allocation of %i bytes failed.", __func__, MAX_MAP_LIGHTING*3);
/* litfile data stored in dlightdata, after the white light */ lit_file_p = 0;
lit_filebase = file_end + 12 - ((uintptr_t)file_end % 12); lit_file_end = (MAX_MAP_LIGHTING*3);
lit_file_p = lit_filebase;
lit_file_end = lit_filebase + 3 * (MAX_MAP_LIGHTING / 4);
/* lux data stored in a separate buffer */ /* lux data stored in a separate buffer */
lux_buffer = (byte *)malloc(bsp->lightdatasize*3); lux_filebase = (byte *)calloc(MAX_MAP_LIGHTING*3, 1);
lux_filebase = lux_buffer + 12 - ((uintptr_t)lux_buffer % 12); if (!lux_filebase)
lux_file_p = lux_filebase; Error("%s: allocation of %i bytes failed.", __func__, MAX_MAP_LIGHTING*3);
lux_file_end = lux_filebase + 3 * (MAX_MAP_LIGHTING / 4); lux_file_p = 0;
lux_file_end = (MAX_MAP_LIGHTING*3);
if (forcedscale) if (forcedscale)
BSPX_AddLump(bspdata, "LMSHIFT", NULL, 0); BSPX_AddLump(bspdata, "LMSHIFT", NULL, 0);
@ -444,7 +462,16 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale)
} }
logprint("Lighting Completed.\n\n"); logprint("Lighting Completed.\n\n");
bsp->lightdatasize = file_p - filebase;
// Transfer greyscale lightmap to the bsp and update lightdatasize
if (!litonly) {
bsp->lightdatasize = file_p;
free(bsp->dlightdata);
bsp->dlightdata = (byte *)malloc(bsp->lightdatasize);
memcpy(bsp->dlightdata, filebase, bsp->lightdatasize);
} else {
// NOTE: bsp->lightdatasize is already valid in the -litonly case
}
logprint("lightdatasize: %i\n", bsp->lightdatasize); logprint("lightdatasize: %i\n", bsp->lightdatasize);
if (faces_sup) { if (faces_sup) {
@ -1046,6 +1073,10 @@ light_main(int argc, const char **argv)
} else if (!strcmp(argv[i], "-arghradcompat")) { //mxd } else if (!strcmp(argv[i], "-arghradcompat")) { //mxd
logprint("Arghrad entity keys conversion enabled\n"); logprint("Arghrad entity keys conversion enabled\n");
arghradcompat = true; arghradcompat = true;
} else if (!strcmp(argv[i], "-litonly")) {
logprint("-litonly specified; .bsp file will not be modified\n");
litonly = true;
write_litfile |= 1;
} else if ( !strcmp( argv[ i ], "-verbose" ) ) { } else if ( !strcmp( argv[ i ], "-verbose" ) ) {
verbose_log = true; verbose_log = true;
} else if ( !strcmp( argv[ i ], "-help" ) ) { } else if ( !strcmp( argv[ i ], "-help" ) ) {
@ -1241,7 +1272,11 @@ light_main(int argc, const char **argv)
WriteEntitiesToString(cfg, bsp); WriteEntitiesToString(cfg, bsp);
/* Convert data format back if necessary */ /* Convert data format back if necessary */
ConvertBSPFormat(loadversion, &bspdata); ConvertBSPFormat(loadversion, &bspdata);
if (!litonly) {
WriteBSPFile(source, &bspdata); WriteBSPFile(source, &bspdata);
}
end = I_FloatTime(); end = I_FloatTime();
logprint("%5.3f seconds elapsed\n", end - start); logprint("%5.3f seconds elapsed\n", end - start);
logprint("\n"); logprint("\n");

View File

@ -2991,10 +2991,58 @@ BoxBlurImage(const std::vector<qvec4f> &input, int w, int h, int radius)
return res; return res;
} }
static void
WriteSingleLightmap(const mbsp_t *bsp,
const bsp2_dface_t *face,
const lightsurf_t *lightsurf,
const lightmap_t *lm,
const int actual_width, const int actual_height,
byte *out, byte *lit, byte *lux);
static void static void
WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const lightsurf_t *lightsurf, WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const lightsurf_t *lightsurf,
const lightmapdict_t *lightmaps) const lightmapdict_t *lightmaps)
{ {
const int actual_width = lightsurf->texsize[0] + 1;
const int actual_height = lightsurf->texsize[1] + 1;
if (litonly) {
// special case for writing a .lit for a bsp without modifying the bsp.
// involves looking at which styles were written to the bsp in the previous lighting run, and then
// writing the same styles to the same offsets in the .lit file.
if (face->lightofs == -1) {
// nothing to write for this face
return;
}
byte *out, *lit, *lux;
GetFileSpace_PreserveOffsetInBsp(&out, &lit, &lux, face->lightofs);
for (int mapnum = 0; mapnum < MAXLIGHTMAPS; mapnum++) {
const int style = face->styles[mapnum];
if (style == 255) {
break; // all done for this face
}
// see if we have computed lighting for this style
for (const lightmap_t& lm : *lightmaps) {
if (lm.style == style) {
WriteSingleLightmap(bsp, face, lightsurf, &lm, actual_width, actual_height, out, lit, lux);
break;
}
}
// if we didn't find a matching lightmap, just don't write anything
out += (actual_width * actual_height);
lit += (actual_width * actual_height * 3);
lux += (actual_width * actual_height * 3);
}
return;
}
// intermediate collection for sorting lightmaps // intermediate collection for sorting lightmaps
std::vector<std::pair<float, const lightmap_t *>> sortable; std::vector<std::pair<float, const lightmap_t *>> sortable;
@ -3069,6 +3117,7 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const
size *= 3; size *= 3;
byte *out, *lit, *lux; byte *out, *lit, *lux;
GetFileSpace(&out, &lit, &lux, size * numstyles); GetFileSpace(&out, &lit, &lux, size * numstyles);
if (facesup) { if (facesup) {
facesup->lightofs = out - filebase; facesup->lightofs = out - filebase;
@ -3084,15 +3133,33 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const
Q_assert(Q_strcasecmp(texname, "trigger") != 0); Q_assert(Q_strcasecmp(texname, "trigger") != 0);
} }
const int actual_width = lightsurf->texsize[0] + 1;
const int actual_height = lightsurf->texsize[1] + 1;
const int oversampled_width = (lightsurf->texsize[0] + 1) * oversample;
const int oversampled_height = (lightsurf->texsize[1] + 1) * oversample;
for (int mapnum = 0; mapnum < numstyles; mapnum++) { for (int mapnum = 0; mapnum < numstyles; mapnum++) {
const lightmap_t *lm = sorted.at(mapnum); const lightmap_t *lm = sorted.at(mapnum);
WriteSingleLightmap(bsp, face, lightsurf, lm, actual_width, actual_height, out, lit, lux);
out += (actual_width * actual_height);
lit += (actual_width * actual_height * 3);
lux += (actual_width * actual_height * 3);
}
}
/**
* - Writes (actual_width * actual_height) bytes to `out`
* - Writes (actual_width * actual_height * 3) bytes to `lit`
* - Writes (actual_width * actual_height * 3) bytes to `lux`
*/
static void
WriteSingleLightmap(const mbsp_t *bsp,
const bsp2_dface_t *face,
const lightsurf_t *lightsurf,
const lightmap_t *lm,
const int actual_width, const int actual_height,
byte *out, byte *lit, byte *lux)
{
const int oversampled_width = actual_width * oversample;
const int oversampled_height = actual_height * oversample;
// allocate new float buffers for the output colors and directions // allocate new float buffers for the output colors and directions
// these are the actual output width*height, without oversampling. // these are the actual output width*height, without oversampling.
@ -3161,7 +3228,6 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const
} }
} }
} }
}
static void LightFaceShutdown(lightsurf_t *lightsurf) static void LightFaceShutdown(lightsurf_t *lightsurf)
{ {
@ -3196,6 +3262,9 @@ LightFace(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const globa
/* One extra lightmap is allocated to simplify handling overflow */ /* One extra lightmap is allocated to simplify handling overflow */
if (!litonly) {
// if litonly is set we need to preserve the existing lightofs
/* some surfaces don't need lightmaps */ /* some surfaces don't need lightmaps */
if (facesup) if (facesup)
{ {
@ -3209,6 +3278,7 @@ LightFace(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const globa
for (int i = 0; i < MAXLIGHTMAPS; i++) for (int i = 0; i < MAXLIGHTMAPS; i++)
face->styles[i] = 255; face->styles[i] = 255;
} }
}
/* don't bother with degenerate faces */ /* don't bother with degenerate faces */
if (face->numedges < 3) if (face->numedges < 3)