diff --git a/include/light/light.hh b/include/light/light.hh index 028736a9..da7633eb 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -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 diff --git a/light/light.cc b/light/light.cc index e0b095e1..817bed5a 100644 --- a/light/light.cc +++ b/light/light.cc @@ -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; std::vector 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"); diff --git a/light/ltface.cc b/light/ltface.cc index 5ce4f001..1542ea29 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -2991,10 +2991,58 @@ BoxBlurImage(const std::vector &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> 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 */