diff --git a/docs/light.rst b/docs/light.rst index 2454c6c3..88f861de 100644 --- a/docs/light.rst +++ b/docs/light.rst @@ -331,6 +331,14 @@ Experimental options Writes both rgb and directions data *only* into the bsp itself. +.. option:: -hdr + + Write .lit file with e5bgr9 data. + +.. option:: -bspxhdr + + Writes e5bgr9 data into the bsp itself. + .. option:: -novanilla Fallback scaled lighting will be omitted. Standard grey lighting will diff --git a/include/light/light.hh b/include/light/light.hh index b5a6728b..5835c558 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -171,7 +171,9 @@ enum class lightfile external = 1, bspx = 2, both = external | bspx, - lit2 = 4 + lit2 = 4, + hdr = 8, + bspxhdr = 16, }; /* tracelist is a std::vector of pointers to modelinfo_t to use for LOS tests */ @@ -393,6 +395,8 @@ public: setting_func bspxlux; setting_func bspxonly; setting_func bspx; + setting_func hdr; + setting_func bspxhdr; setting_scalar world_units_per_luxel; setting_bool litonly; setting_bool nolights; diff --git a/include/light/write.hh b/include/light/write.hh index 9d685bec..766e3bba 100644 --- a/include/light/write.hh +++ b/include/light/write.hh @@ -29,6 +29,7 @@ struct mbsp_t; struct bspdata_t; constexpr int32_t LIT_VERSION = 1; +constexpr int32_t LIT_VERSION_E5BGR9 = (0x00010000 | LIT_VERSION); struct litheader_t { @@ -67,7 +68,7 @@ struct facesup_t twosided extent; }; -void WriteLitFile(const mbsp_t *bsp, const std::vector &facesup, const fs::path &filename, int version, const std::vector &lit_filebase, const std::vector &lux_filebase); +void WriteLitFile(const mbsp_t *bsp, const std::vector &facesup, const fs::path &filename, int version, const std::vector &lit_filebase, const std::vector &lux_filebase, const std::vector &hdr_filebase); void WriteLuxFile(const mbsp_t *bsp, const fs::path &filename, int version, const std::vector &lux_filebase); void SaveLightmapSurfaces(bspdata_t *bspdata, const fs::path &source); diff --git a/light/light.cc b/light/light.cc index a971fcf9..58cf20a0 100644 --- a/light/light.cc +++ b/light/light.cc @@ -333,6 +333,18 @@ light_settings::light_settings() write_luxfile = lightfile::bspx; }, &experimental_group, "writes both rgb and directions data into the bsp itself"}, + hdr{this, "hdr", + [&](source) { + write_litfile |= lightfile::external; + write_litfile |= lightfile::hdr; + }, + &experimental_group, "write .lit file with e5bgr9 data"}, + bspxhdr{this, "bspxhdr", + [&](source) { + write_litfile |= lightfile::hdr; + write_litfile |= lightfile::bspxhdr; + }, + &experimental_group, "writes e5bgr9 data into the bsp itself"}, world_units_per_luxel{ this, "world_units_per_luxel", 0, 0, 1024, &output_group, "enables output of DECOUPLED_LM BSPX lump"}, litonly{this, "litonly", false, &output_group, "only write .lit file, don't modify BSP"}, diff --git a/light/ltface.cc b/light/ltface.cc index b7fc2189..815cb16b 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -2453,14 +2453,6 @@ static void LightPoint_ScaleAndClamp(qvec3f &color) c = pow(c / 255.0f, 1.0f / cfg.lightmapgamma.value()) * 255.0f; } } - - // clamp - // FIXME: should this be a brightness clamp? - float maxcolor = qv::max(color); - - if (maxcolor > 255.0f) { - color *= (255.0f / maxcolor); - } } static void LightPoint_ScaleAndClamp(lightgrid_samples_t &result) diff --git a/light/write.cc b/light/write.cc index 6d5c83ed..2f557d95 100644 --- a/light/write.cc +++ b/light/write.cc @@ -48,7 +48,8 @@ void litheader_t::v2_t::stream_read(std::istream &s) s >= std::tie(numsurfs, lmsamples); } -void WriteLitFile(const mbsp_t *bsp, const std::vector &facesup, const fs::path &filename, int version, const std::vector &lit_filebase, const std::vector &lux_filebase) +void WriteLitFile(const mbsp_t *bsp, const std::vector &facesup, const fs::path &filename, int version, + const std::vector &lit_filebase, const std::vector &lux_filebase, const std::vector &hdr_filebase) { litheader_t header; @@ -80,8 +81,13 @@ void WriteLitFile(const mbsp_t *bsp, const std::vector &facesup, cons } litfile.write((const char *)lit_filebase.data(), bsp->dlightdata.size() * 3); litfile.write((const char *)lux_filebase.data(), bsp->dlightdata.size() * 3); - } else - litfile.write((const char *)lit_filebase.data(), bsp->dlightdata.size() * 3); + } else { + if (version == LIT_VERSION_E5BGR9) { + litfile.write((const char *)hdr_filebase.data(), bsp->dlightdata.size() * 4); + } else { + litfile.write((const char *)lit_filebase.data(), bsp->dlightdata.size() * 3); + } + } } void WriteLuxFile(const mbsp_t *bsp, const fs::path &filename, int version, const std::vector &lux_filebase) @@ -365,14 +371,41 @@ static std::vector BoxBlurImage(const std::vector &input, int w, return res; } +static unsigned int HDR_PackResult(qvec4f rgba) +{ +#define HDR_ONE 128.0f // logical value for 1.0 lighting (quake's overbrights give 255). + // we want 0-1-like values. except that we can oversample and express smaller values too. + float r = rgba[0] / HDR_ONE; + float g = rgba[1] / HDR_ONE; + float b = rgba[2] / HDR_ONE; + + int e = 0; + float m = std::max(std::max(r, g), b); + float scale; + + if (m >= 0.5f) { // positive exponent + while (m >= (1 << (e)) && e < 30 - 15) // don't do nans. + e++; + } else { // negative exponent... + while (m < 1 / (1 << -e) && e > -15) // don't do nans. + e--; + } + + scale = powf(2, (float)e - 9); + + return ((e + 15) << 27) | (std::min((int)std::lround(b / scale + 0.5f), 0x1ff) << 18) | + (std::min((int)std::lround(g / scale + 0.5f), 0x1ff) << 9) | + (std::min((int)std::lround(r / scale + 0.5f), 0x1ff) << 0); +} + /** * - 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 mface_t *face, const lightsurf_t *lightsurf, - const lightmap_t *lm, const int actual_width, const int actual_height, uint8_t *out, uint8_t *lit, uint8_t *lux, - const faceextents_t &output_extents) + const lightmap_t *lm, const int actual_width, const int actual_height, + uint8_t *out, uint8_t *lit, uint8_t *lux, uint8_t *hdr, const faceextents_t &output_extents) { const int oversampled_width = actual_width * light_options.extra.value(); const int oversampled_height = actual_height * light_options.extra.value(); @@ -413,7 +446,23 @@ static void WriteSingleLightmap(const mbsp_t *bsp, const mface_t *face, const li const int sampleindex = (input_sample_t * actual_width) + input_sample_s; if (lit || out) { - const qvec4f &color = output_color.at(sampleindex); + qvec4f color = output_color.at(sampleindex); + + if (hdr) { + unsigned int c = HDR_PackResult(color); + *hdr++ = c & 0xFF; + *hdr++ = (c >> 8) & 0xFF; + *hdr++ = (c >> 16) & 0xFF; + *hdr++ = (c >> 24) & 0xFF; + } + + // clamp + // FIXME: should this be a brightness clamp? + const float maxcolor = qv::max(color); + + if (maxcolor > 255.0f) { + color *= (255.0f / maxcolor); + } if (lit) { *lit++ = color[0]; @@ -465,7 +514,8 @@ static void WriteSingleLightmap(const mbsp_t *bsp, const mface_t *face, const li * - Writes (output_width * output_height * 3) bytes to `lux` */ static void WriteSingleLightmap_FromDecoupled(const mbsp_t *bsp, const mface_t *face, const lightsurf_t *lightsurf, - const lightmap_t *lm, const int output_width, const int output_height, uint8_t *out, uint8_t *lit, uint8_t *lux) + const lightmap_t *lm, const int output_width, const int output_height, + uint8_t *out, uint8_t *lit, uint8_t *lux, uint8_t *hdr) { // this is the lightmap data in the "decoupled" coordinate system std::vector fullres = LightmapColorsToGLMVector(lightsurf, lm); @@ -501,11 +551,27 @@ static void WriteSingleLightmap_FromDecoupled(const mbsp_t *bsp, const mface_t * const float coord_frac_y = decoupled_lm_coord[1] - coord_floor_y; // 2D bilinear interpolation - const qvec4f color = + qvec4f color = mix(mix(tex(coord_floor_x, coord_floor_y), tex(coord_floor_x + 1, coord_floor_y), coord_frac_x), mix(tex(coord_floor_x, coord_floor_y + 1), tex(coord_floor_x + 1, coord_floor_y + 1), coord_frac_x), coord_frac_y); + if (hdr) { + unsigned int c = HDR_PackResult(color); + *hdr++ = c & 0xFF; + *hdr++ = (c >> 8) & 0xFF; + *hdr++ = (c >> 16) & 0xFF; + *hdr++ = (c >> 24) & 0xFF; + } + + // clamp + // FIXME: should this be a brightness clamp? + const float maxcolor = qv::max(color); + + if (maxcolor > 255.0f) { + color *= (255.0f / maxcolor); + } + if (lit || out) { if (lit) { *lit++ = color[0]; @@ -567,14 +633,6 @@ inline void LightFace_ScaleAndClamp(lightsurf_t *lightsurf) c = pow(c / 255.0f, 1.0f / cfg.lightmapgamma.value()) * 255.0f; } } - - // clamp - // FIXME: should this be a brightness clamp? - float maxcolor = qv::max(color); - - if (maxcolor > 255.0f) { - color *= (255.0f / maxcolor); - } } } } @@ -607,9 +665,9 @@ static float Lightmap_MaxBrightness(const lightmap_t *lm, const lightsurf_t *lig return maxb; } -static void SaveLitOnlyLightmapSurface(const mbsp_t *bsp, mface_t *face, - lightsurf_t *lightsurf, const faceextents_t &extents, - const faceextents_t &output_extents, std::vector &filebase, std::vector &lit_filebase, std::vector &lux_filebase) +static void SaveLitOnlyLightmapSurface(const mbsp_t *bsp, mface_t *face, lightsurf_t *lightsurf, + const faceextents_t &extents, const faceextents_t &output_extents, std::vector &filebase, + std::vector &lit_filebase, std::vector &lux_filebase, std::vector &hdr_filebase) { lightmapdict_t &lightmaps = lightsurf->lightmapsByStyle; const int actual_width = extents.width(); @@ -625,7 +683,7 @@ static void SaveLitOnlyLightmapSurface(const mbsp_t *bsp, mface_t *face, return; } - uint8_t *out = nullptr, *lit = nullptr, *lux = nullptr; + uint8_t *out = nullptr, *lit = nullptr, *lux = nullptr, *hdr = nullptr; Q_assert(face->lightofs >= 0); @@ -641,6 +699,10 @@ static void SaveLitOnlyLightmapSurface(const mbsp_t *bsp, mface_t *face, lux = lux_filebase.data() + (face->lightofs * 3); } + if (!hdr_filebase.empty()) { + hdr = hdr_filebase.data() + (face->lightofs * 4); + } + // NOTE: file_p et. al. are not updated, since we're not dynamically allocating the lightmaps for (int mapnum = 0; mapnum < MAXLIGHTMAPS; mapnum++) { @@ -654,7 +716,7 @@ static void SaveLitOnlyLightmapSurface(const mbsp_t *bsp, mface_t *face, for (const lightmap_t &lm : lightmaps) { if (lm.style == style) { WriteSingleLightmap( - bsp, face, lightsurf, &lm, actual_width, actual_height, out, lit, lux, output_extents); + bsp, face, lightsurf, &lm, actual_width, actual_height, out, lit, lux, hdr, output_extents); break; } } @@ -669,6 +731,9 @@ static void SaveLitOnlyLightmapSurface(const mbsp_t *bsp, mface_t *face, if (lux) { lux += (size * 3); } + if (hdr) { + hdr += (size * 4); + } } } @@ -718,9 +783,10 @@ int CalculateLightmapStyles(const mbsp_t *bsp, mface_t *face, facesup_t *facesup 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, - // the face is drawn fullbright instead of black (Q1) + // skip lightmaps where all samples have brightness below 1 unless rendering float lightmaps + // HACK: don't do this on Q2. seems if all styles are 0xff, + // the face is drawn fullbright instead of black (Q1) + if (bsp->loadversion->game->id != GAME_QUAKE_II && !(light_options.write_litfile & lightfile::hdr)) { const float maxb = Lightmap_MaxBrightness(&lightmap, lightsurf); if (maxb < 1) continue; @@ -787,9 +853,8 @@ int CalculateLightmapStyles(const mbsp_t *bsp, mface_t *face, facesup_t *facesup void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, bspx_decoupled_lm_perface *facesup_decoupled, lightsurf_t *lightsurf, const faceextents_t &extents, - const faceextents_t &output_extents, - std::vector &filebase, std::vector &lit_filebase, std::vector &lux_filebase, - lightmap_intermediate_data_t &id) + const faceextents_t &output_extents, std::vector &filebase, std::vector &lit_filebase, + std::vector &lux_filebase, std::vector &hdr_filebase, lightmap_intermediate_data_t &id) { const int output_width = output_extents.width(); const int output_height = output_extents.height(); @@ -830,7 +895,7 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, } } - uint8_t *out = nullptr, *lit = nullptr, *lux = nullptr; + uint8_t *out = nullptr, *lit = nullptr, *lux = nullptr, *hdr = nullptr; if (!filebase.empty()) { out = filebase.data() + id.lightofs; @@ -844,6 +909,10 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, lux = lux_filebase.data() + (id.lightofs * 3); } + if (!hdr_filebase.empty()) { + hdr = hdr_filebase.data() + (id.lightofs * 4); + } + int lightofs; // Q2/HL native colored lightmaps @@ -881,10 +950,14 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, Q_assert((lux - lux_filebase.data()) + (size * 3 * id.sorted.size()) <= lux_filebase.size()); } + if (hdr) { + Q_assert((hdr - hdr_filebase.data()) + (size * 4 * id.sorted.size()) <= hdr_filebase.size()); + } + for (int mapnum = 0; mapnum < id.sorted.size(); mapnum++) { const lightmap_t *lm = id.sorted.at(mapnum); - WriteSingleLightmap(bsp, face, lightsurf, lm, actual_width, actual_height, out, lit, lux, output_extents); + WriteSingleLightmap(bsp, face, lightsurf, lm, actual_width, actual_height, out, lit, lux, hdr, output_extents); if (out) { out += size; @@ -895,6 +968,9 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, if (lux) { lux += (size * 3); } + if (hdr) { + hdr += (size * 4); + } } // write vanilla lightmap if -world_units_per_luxel is in use but not -novanilla @@ -915,6 +991,10 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, lux = lux_filebase.data() + (id.vanilla_lightofs * 3); } + if (!hdr_filebase.empty()) { + hdr = hdr_filebase.data() + (id.vanilla_lightofs * 4); + } + // Q2/HL native colored lightmaps if (bsp->loadversion->game->has_rgb_lightmap) { lightofs = lit - lit_filebase.data(); @@ -927,7 +1007,7 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, const lightmap_t *lm = id.sorted.at(mapnum); WriteSingleLightmap_FromDecoupled(bsp, face, lightsurf, lm, lightsurf->vanilla_extents.width(), - lightsurf->vanilla_extents.height(), out, lit, lux); + lightsurf->vanilla_extents.height(), out, lit, lux, hdr); if (out) { out += vanilla_size; @@ -938,6 +1018,9 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, if (lux) { lux += (vanilla_size * 3); } + if (hdr) { + hdr += (vanilla_size * 4); + } } } } @@ -952,7 +1035,7 @@ void SaveLightmapSurfaces(bspdata_t *bspdata, const fs::path &source) fully_transparent_lightmaps = 0; // lightmap data storage - std::vector filebase, lit_filebase, lux_filebase; + std::vector filebase, lit_filebase, lux_filebase, hdr_filebase; if (light_options.litonly.value()) { @@ -971,7 +1054,11 @@ void SaveLightmapSurfaces(bspdata_t *bspdata, const fs::path &source) if (light_options.write_luxfile) { lux_filebase.resize(filebase.size() * 3); } - + + if (light_options.write_litfile & lightfile::hdr) { + hdr_filebase.resize(filebase.size() * 4); + } + logging::parallel_for(static_cast(0), bsp->dfaces.size(), [&](size_t i) { auto &surf = LightSurfaces()[i]; @@ -983,7 +1070,8 @@ void SaveLightmapSurfaces(bspdata_t *bspdata, const fs::path &source) auto f = &bsp->dfaces[i]; - SaveLitOnlyLightmapSurface(bsp, f, &surf, surf.extents, surf.extents, filebase, lit_filebase, lux_filebase); + SaveLitOnlyLightmapSurface( + bsp, f, &surf, surf.extents, surf.extents, filebase, lit_filebase, lux_filebase, hdr_filebase); }); } else { std::atomic_size_t lightmap_size = 0; @@ -1006,21 +1094,26 @@ void SaveLightmapSurfaces(bspdata_t *bspdata, const fs::path &source) int num_styles; if (!facesup_decoupled_global.empty()) { - num_styles = CalculateLightmapStyles( - bsp, f, nullptr, &surf, surf.extents, lightmap_size, intermediate_data[i]); + num_styles = + CalculateLightmapStyles(bsp, f, nullptr, &surf, surf.extents, lightmap_size, intermediate_data[i]); if (!light_options.novanilla.value()) { - intermediate_data[i].vanilla_lightofs = GetFileSpace(lightmap_size, surf.vanilla_extents.numsamples() * num_styles); + intermediate_data[i].vanilla_lightofs = + GetFileSpace(lightmap_size, surf.vanilla_extents.numsamples() * num_styles); } } else if (faces_sup.empty()) { - num_styles = CalculateLightmapStyles(bsp, f, nullptr, &surf, surf.extents, lightmap_size, intermediate_data[i]); + num_styles = + CalculateLightmapStyles(bsp, f, nullptr, &surf, surf.extents, lightmap_size, intermediate_data[i]); } else if (light_options.novanilla.value() || faces_sup[i].lmscale == face_modelinfo->lightmapscale) { - num_styles = CalculateLightmapStyles(bsp, f, &faces_sup[i], &surf, surf.extents, lightmap_size, intermediate_data[i]); + num_styles = CalculateLightmapStyles( + bsp, f, &faces_sup[i], &surf, surf.extents, lightmap_size, intermediate_data[i]); } else { - num_styles = CalculateLightmapStyles(bsp, f, nullptr, &surf, surf.extents, lightmap_size, intermediate_data[i]); - intermediate_data[i].vanilla_lightofs = GetFileSpace(lightmap_size, surf.vanilla_extents.numsamples() * num_styles); + num_styles = + CalculateLightmapStyles(bsp, f, nullptr, &surf, surf.extents, lightmap_size, intermediate_data[i]); + intermediate_data[i].vanilla_lightofs = + GetFileSpace(lightmap_size, surf.vanilla_extents.numsamples() * num_styles); } - + if (num_styles) { intermediate_data[i].lightofs = GetFileSpace(lightmap_size, surf.extents.numsamples() * num_styles); } @@ -1039,7 +1132,12 @@ void SaveLightmapSurfaces(bspdata_t *bspdata, const fs::path &source) lux_filebase.resize(lightmap_size * 3); } - logging::print(logging::flag::STAT, "lightmap size (total): {}\n", filebase.size() + lit_filebase.size() + lux_filebase.size()); + if (light_options.write_litfile & lightfile::hdr) { + hdr_filebase.resize(lightmap_size * 4); + } + + logging::print(logging::flag::STAT, "lightmap size (total): {}\n", + filebase.size() + lit_filebase.size() + lux_filebase.size() + hdr_filebase.size()); logging::parallel_for(static_cast(0), bsp->dfaces.size(), [&](size_t i) { auto &surf = LightSurfaces()[i]; @@ -1052,24 +1150,28 @@ void SaveLightmapSurfaces(bspdata_t *bspdata, const fs::path &source) const modelinfo_t *face_modelinfo = ModelInfoForFace(bsp, i); if (!facesup_decoupled_global.empty()) { - SaveLightmapSurface( - bsp, f, nullptr, &facesup_decoupled_global[i], &surf, surf.extents, surf.extents, filebase, lit_filebase, lux_filebase, intermediate_data[i]); + SaveLightmapSurface(bsp, f, nullptr, &facesup_decoupled_global[i], &surf, surf.extents, surf.extents, + filebase, lit_filebase, lux_filebase, hdr_filebase, intermediate_data[i]); } else if (faces_sup.empty()) { - SaveLightmapSurface(bsp, f, nullptr, nullptr, &surf, surf.extents, surf.extents, filebase, lit_filebase, lux_filebase, intermediate_data[i]); + SaveLightmapSurface(bsp, f, nullptr, nullptr, &surf, surf.extents, surf.extents, filebase, lit_filebase, + lux_filebase, hdr_filebase, intermediate_data[i]); } else if (light_options.novanilla.value() || faces_sup[i].lmscale == face_modelinfo->lightmapscale) { if (faces_sup[i].lmscale == face_modelinfo->lightmapscale) { f->lightofs = faces_sup[i].lightofs; } else { f->lightofs = -1; } - SaveLightmapSurface(bsp, f, &faces_sup[i], nullptr, &surf, surf.extents, surf.extents, filebase, lit_filebase, lux_filebase, intermediate_data[i]); + SaveLightmapSurface(bsp, f, &faces_sup[i], nullptr, &surf, surf.extents, surf.extents, filebase, + lit_filebase, lux_filebase, hdr_filebase, intermediate_data[i]); for (int j = 0; j < MAXLIGHTMAPS; j++) { f->styles[j] = faces_sup[i].styles[j] == INVALID_LIGHTSTYLE ? INVALID_LIGHTSTYLE_OLD : faces_sup[i].styles[j]; } } else { - SaveLightmapSurface(bsp, f, nullptr, nullptr, &surf, surf.extents, surf.vanilla_extents, filebase, lit_filebase, lux_filebase, intermediate_data[i]); - SaveLightmapSurface(bsp, f, &faces_sup[i], nullptr, &surf, surf.extents, surf.extents, filebase, lit_filebase, lux_filebase, intermediate_data[i]); + SaveLightmapSurface(bsp, f, nullptr, nullptr, &surf, surf.extents, surf.vanilla_extents, filebase, + lit_filebase, lux_filebase, hdr_filebase, intermediate_data[i]); + SaveLightmapSurface(bsp, f, &faces_sup[i], nullptr, &surf, surf.extents, surf.extents, filebase, + lit_filebase, lux_filebase, hdr_filebase, intermediate_data[i]); } }); } @@ -1077,7 +1179,7 @@ void SaveLightmapSurfaces(bspdata_t *bspdata, const fs::path &source) logging::print("Lighting Completed.\n\n"); if (light_options.write_litfile == lightfile::lit2) { - WriteLitFile(bsp, faces_sup, source, 2, lit_filebase, lux_filebase); + WriteLitFile(bsp, faces_sup, source, 2, lit_filebase, lux_filebase, hdr_filebase); return; // run away before any files are written } @@ -1093,12 +1195,14 @@ void SaveLightmapSurfaces(bspdata_t *bspdata, const fs::path &source) bspdata->bspx.entries.erase("RGBLIGHTING"); bspdata->bspx.entries.erase("LIGHTINGDIR"); + bspdata->bspx.entries.erase("LIGHTING_E5BGR9"); // lit/lux files (or their BSPX equivalents) - only write in games that lack RGB lightmaps. // (technically we could allow .lux in Q2 mode, but no engines support it.) if (!bsp->loadversion->game->has_rgb_lightmap) { if (light_options.write_litfile & lightfile::external) { - WriteLitFile(bsp, faces_sup, source, LIT_VERSION, lit_filebase, lux_filebase); + int version = light_options.write_litfile & lightfile::hdr ? LIT_VERSION_E5BGR9 : LIT_VERSION; + WriteLitFile(bsp, faces_sup, source, version, lit_filebase, lux_filebase, hdr_filebase); } if (light_options.write_litfile & lightfile::bspx) { lit_filebase.resize(bsp->dlightdata.size() * 3); @@ -1111,5 +1215,9 @@ void SaveLightmapSurfaces(bspdata_t *bspdata, const fs::path &source) lux_filebase.resize(bsp->dlightdata.size() * 3); bspdata->bspx.transfer("LIGHTINGDIR", lux_filebase); } + if (light_options.write_litfile & lightfile::bspxhdr) { + hdr_filebase.resize(bsp->dlightdata.size() * 4); + bspdata->bspx.transfer("LIGHTING_E5BGR9", hdr_filebase); + } } }