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 qboolean novisapprox;
extern bool nolights;
extern bool litonly;
typedef enum {
backend_bsp,
@ -417,6 +418,7 @@ lockable_setting_t *FindSetting(std::string name);
void SetGlobalSetting(std::string name, std::string value, bool cmdline);
void FixupGlobalSettings(void);
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 *ModelInfoForFace(const mbsp_t *bsp, int facenum);
//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
byte *filebase; // start of lightmap data
static byte *file_p; // start of free space after data
static byte *file_end; // end of free space for lightmap data
/// start of lightmap data
byte *filebase;
/// 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
static byte *lit_file_p; // start of free space after litfile data
static byte *lit_file_end; // end of space for litfile data
/// start of litfile data
byte *lit_filebase;
/// 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)
byte *lux_filebase; // start of luxfile data
static byte *lux_file_p; // start of free space after luxfile data
static byte *lux_file_end; // end of space for luxfile data
/// start of luxfile data
byte *lux_filebase;
/// offset of start of free space after luxfile data (should be kept a multiple of 12)
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<const modelinfo_t *> tracelist;
@ -96,6 +104,7 @@ backend_t rtbackend = backend_embree;
bool debug_highlightseams = false;
debugmode_t debugmode = debugmode_none;
bool verbose_log = false;
bool litonly = false;
uint64_t *extended_texinfo_flags = NULL;
@ -172,26 +181,20 @@ GetFileSpace(byte **lightdata, byte **colordata, byte **deluxdata, int size)
{
ThreadLock();
/* align to 4 byte boudaries */
file_p = (byte *)(((uintptr_t)file_p + 3) & ~3);
*lightdata = file_p;
*lightdata = filebase + file_p;
*colordata = lit_filebase + lit_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;
if (colordata) {
/* 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;
}
lit_file_p += 3 * size;
lux_file_p += 3 * size;
ThreadUnlock();
@ -202,6 +205,26 @@ GetFileSpace(byte **lightdata, byte **colordata, byte **deluxdata, int size)
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)
{
return modelinfo.at(modelnum);
@ -362,35 +385,30 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale)
logprint("--- LightWorld ---\n" );
mbsp_t *const bsp = &bspdata->data.mbsp;
if (bsp->dlightdata)
free(bsp->dlightdata);
if (lux_buffer)
free(lux_buffer);
free(filebase);
free(lit_filebase);
free(lux_filebase);
/* FIXME - remove this limit */
bsp->lightdatasize = MAX_MAP_LIGHTING;
bsp->dlightdata = (byte *)malloc(bsp->lightdatasize + 16); /* for alignment */
if (!bsp->dlightdata)
Error("%s: allocation of %i bytes failed.",
__func__, bsp->lightdatasize);
memset(bsp->dlightdata, 0, bsp->lightdatasize + 16);
bsp->lightdatasize /= 4;
/* greyscale data stored in a separate buffer */
filebase = (byte *)calloc(MAX_MAP_LIGHTING, 1);
if (!filebase)
Error("%s: allocation of %i bytes failed.", __func__, MAX_MAP_LIGHTING);
file_p = 0;
file_end = MAX_MAP_LIGHTING;
/* align filebase to a 4 byte boundary */
filebase = file_p = (byte *)(((uintptr_t)bsp->dlightdata + 3) & ~3);
file_end = filebase + bsp->lightdatasize;
/* litfile data stored in dlightdata, after the white light */
lit_filebase = file_end + 12 - ((uintptr_t)file_end % 12);
lit_file_p = lit_filebase;
lit_file_end = lit_filebase + 3 * (MAX_MAP_LIGHTING / 4);
/* litfile data stored in a separate buffer */
lit_filebase = (byte *)calloc(MAX_MAP_LIGHTING*3, 1);
if (!lit_filebase)
Error("%s: allocation of %i bytes failed.", __func__, MAX_MAP_LIGHTING*3);
lit_file_p = 0;
lit_file_end = (MAX_MAP_LIGHTING*3);
/* lux data stored in a separate buffer */
lux_buffer = (byte *)malloc(bsp->lightdatasize*3);
lux_filebase = lux_buffer + 12 - ((uintptr_t)lux_buffer % 12);
lux_file_p = lux_filebase;
lux_file_end = lux_filebase + 3 * (MAX_MAP_LIGHTING / 4);
lux_filebase = (byte *)calloc(MAX_MAP_LIGHTING*3, 1);
if (!lux_filebase)
Error("%s: allocation of %i bytes failed.", __func__, MAX_MAP_LIGHTING*3);
lux_file_p = 0;
lux_file_end = (MAX_MAP_LIGHTING*3);
if (forcedscale)
BSPX_AddLump(bspdata, "LMSHIFT", NULL, 0);
@ -444,7 +462,16 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale)
}
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);
if (faces_sup) {
@ -1046,6 +1073,10 @@ light_main(int argc, const char **argv)
} else if (!strcmp(argv[i], "-arghradcompat")) { //mxd
logprint("Arghrad entity keys conversion enabled\n");
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" ) ) {
verbose_log = true;
} else if ( !strcmp( argv[ i ], "-help" ) ) {
@ -1241,7 +1272,11 @@ light_main(int argc, const char **argv)
WriteEntitiesToString(cfg, bsp);
/* Convert data format back if necessary */
ConvertBSPFormat(loadversion, &bspdata);
WriteBSPFile(source, &bspdata);
if (!litonly) {
WriteBSPFile(source, &bspdata);
}
end = I_FloatTime();
logprint("%5.3f seconds elapsed\n", end - start);
logprint("\n");

View File

@ -2991,10 +2991,58 @@ BoxBlurImage(const std::vector<qvec4f> &input, int w, int h, int radius)
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
WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const lightsurf_t *lightsurf,
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
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;
byte *out, *lit, *lux;
GetFileSpace(&out, &lit, &lux, size * numstyles);
if (facesup) {
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);
}
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++) {
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
// these are the actual output width*height, without oversampling.
@ -3160,7 +3227,6 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const
}
}
}
}
}
static void LightFaceShutdown(lightsurf_t *lightsurf)
@ -3195,19 +3261,23 @@ LightFace(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const globa
}
/* 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 */
if (facesup)
{
facesup->lightofs = -1;
for (int i = 0; i < MAXLIGHTMAPS; i++)
facesup->styles[i] = 255;
}
else
{
face->lightofs = -1;
for (int i = 0; i < MAXLIGHTMAPS; i++)
face->styles[i] = 255;
/* some surfaces don't need lightmaps */
if (facesup)
{
facesup->lightofs = -1;
for (int i = 0; i < MAXLIGHTMAPS; i++)
facesup->styles[i] = 255;
}
else
{
face->lightofs = -1;
for (int i = 0; i < MAXLIGHTMAPS; i++)
face->styles[i] = 255;
}
}
/* don't bother with degenerate faces */