light: wip -world_units_per_luxel and DECOUPLED_LM BSPX lump

This commit is contained in:
Eric Wasylishen 2022-11-02 09:57:44 -06:00
parent 8b524cf324
commit ca0efbf3d3
10 changed files with 274 additions and 33 deletions

View File

@ -96,6 +96,33 @@ static json serialize_bspxbrushlist(const std::vector<uint8_t> &lump)
return j;
}
static json serialize_bspx_decoupled_lm(const std::vector<uint8_t> &lump)
{
json j = json::array();
imemstream p(lump.data(), lump.size(), std::ios_base::in | std::ios_base::binary);
p >> endianness<std::endian::little>;
while (true) {
bspx_decoupled_lm_perface src_face;
p >= src_face;
if (!p) {
break;
}
json &model = j.insert(j.end(), json::object()).value();
model["lmwidth"] = src_face.lmwidth;
model["lmheight"] = src_face.lmheight;
model["offset"] = src_face.offset;
model["world_to_lm_space"] =
json::array({src_face.world_to_lm_space.row(0), src_face.world_to_lm_space.row(1)});
}
return j;
}
/**
* The MIT License (MIT)
* Copyright (c) 2016 tomykaira
@ -191,8 +218,15 @@ static std::string serialize_image(const std::optional<img::texture> &texture_op
#include "common/bsputils.hh"
static faceextents_t get_face_extents(const mbsp_t &bsp, const bspxentries_t &bspx, const mface_t &face, bool use_bspx)
static faceextents_t get_face_extents(const mbsp_t &bsp, const bspxentries_t &bspx,
const std::vector<bspx_decoupled_lm_perface> &bspx_decoupled, const mface_t &face, bool use_bspx,
bool use_decoupled)
{
if (use_decoupled) {
ptrdiff_t face_idx = &face - bsp.dfaces.data();
auto &bspx = bspx_decoupled[face_idx];
return {face, bsp, bspx.lmwidth, bspx.lmheight, bspx.world_to_lm_space};
}
if (!use_bspx) {
return {face, bsp, 16.0};
}
@ -201,7 +235,7 @@ static faceextents_t get_face_extents(const mbsp_t &bsp, const bspxentries_t &bs
(float)nth_bit(reinterpret_cast<const char *>(bspx.at("LMSHIFT").data())[&face - bsp.dfaces.data()])};
}
static void export_obj_and_lightmaps(const mbsp_t &bsp, const bspxentries_t &bspx, bool use_bspx, fs::path obj_path, fs::path lightmaps_path)
static void export_obj_and_lightmaps(const mbsp_t &bsp, const bspxentries_t &bspx, bool use_bspx, bool use_decoupled, fs::path obj_path, fs::path lightmaps_path)
{
struct face_rect
{
@ -235,18 +269,38 @@ static void export_obj_and_lightmaps(const mbsp_t &bsp, const bspxentries_t &bsp
bspx_lmoffset >> endianness<std::endian::little>;
}
std::vector<bspx_decoupled_lm_perface> bspx_decoupled;
if (use_decoupled && (bspx.find("DECOUPLED_LM") != bspx.end())) {
bspx_decoupled.resize(bsp.dfaces.size());
imemstream stream(nullptr, 0);
auto &decoupled_lm = bspx.at("DECOUPLED_LM");
stream = imemstream(decoupled_lm.data(), decoupled_lm.size());
stream >> endianness<std::endian::little>;
for (size_t i = 0; i < bsp.dfaces.size(); ++i) {
stream >= bspx_decoupled[i];
}
} else {
use_decoupled = false;
}
// make rectangles
for (auto &face : bsp.dfaces) {
const ptrdiff_t face_idx = (&face - bsp.dfaces.data());
int32_t faceofs;
if (!use_bspx) {
if (use_decoupled) {
faceofs = bspx_decoupled[face_idx].offset;
} else if (!use_bspx) {
faceofs = face.lightofs;
} else {
bspx_lmoffset.seekg((&face - bsp.dfaces.data()) * sizeof(int32_t));
bspx_lmoffset.seekg(face_idx * sizeof(int32_t));
bspx_lmoffset >= faceofs;
}
rectangles.emplace_back(face_rect{&face, get_face_extents(bsp, bspx, face, use_bspx), faceofs});
rectangles.emplace_back(face_rect{&face, get_face_extents(bsp, bspx, bspx_decoupled, face, use_bspx, use_decoupled), faceofs});
}
if (!rectangles.size()) {
@ -684,6 +738,8 @@ void serialize_bsp(const bspdata_t &bspdata, const mbsp_t &bsp, const fs::path &
if (lump.first == "BRUSHLIST") {
entry["models"] = serialize_bspxbrushlist(lump.second);
} else if (lump.first == "DECOUPLED_LM") {
entry["faces"] = serialize_bspx_decoupled_lm(lump.second);
} else {
// unhandled BSPX lump, just write the raw data
entry["lumpdata"] = hex_string(lump.second.data(), lump.second.size());
@ -705,7 +761,7 @@ void serialize_bsp(const bspdata_t &bspdata, const mbsp_t &bsp, const fs::path &
}
}
#endif
export_obj_and_lightmaps(bsp, bspdata.bspx.entries, false, fs::path(name).replace_extension(".geometry.obj"), fs::path(name).replace_extension(".lm.png"));
export_obj_and_lightmaps(bsp, bspdata.bspx.entries, false, true, fs::path(name).replace_extension(".geometry.obj"), fs::path(name).replace_extension(".lm.png"));
std::ofstream(name, std::fstream::out | std::fstream::trunc) << std::setw(4) << j;
}

View File

@ -745,6 +745,107 @@ faceextents_t::faceextents_t(const mface_t &face, const mbsp_t &bsp, float light
worldToLMMatrix = TexCoordToLMMatrix * worldToTexCoordMatrix;
}
faceextents_t::faceextents_t(const mface_t &face, const mbsp_t &bsp, uint16_t lmwidth, uint16_t lmheight, texvecf world_to_lm_space) {
if (lmwidth > 0 && lmheight > 0) {
lm_extents = {lmwidth - 1, lmheight - 1};
}
worldToTexCoordMatrix = WorldToTexSpace(&bsp, &face);
texCoordToWorldMatrix = TexSpaceToWorld(&bsp, &face);
worldToLMMatrix.set_row(0, world_to_lm_space.row(0));
worldToLMMatrix.set_row(1, world_to_lm_space.row(1));
worldToLMMatrix.set_row(2, {0, 0, 1, 0});
worldToLMMatrix.set_row(3, {0, 0, 0, 1});
lmToWorldMatrix = qv::inverse(worldToLMMatrix);
// bounds
for (int i = 0; i < face.numedges; i++) {
const qvec3f &worldpoint = Face_PointAtIndex(&bsp, &face, i);
bounds += worldpoint;
}
// calculate a bounding sphere for the face
qvec3d radius = (bounds.maxs() - bounds.mins()) * 0.5;
origin = bounds.mins() + radius;
this->radius = qv::length(radius);
}
faceextents_t::faceextents_t(const mface_t &face, const mbsp_t &bsp, world_units_per_luxel_t tag, float world_units_per_luxel)
{
auto orig_normal = Face_Normal(&bsp, &face);
size_t axis = qv::indexOfLargestMagnitudeComponent(orig_normal);
#if 0
if (orig_normal == qvec3f(-1, 0, 0)) {
logging::print("-x\n");
}
#endif
qvec3f snapped_normal{};
if (orig_normal[axis] > 0) {
snapped_normal[axis] = 1;
} else {
snapped_normal[axis] = -1;
}
auto [t, b] = qv::MakeTangentAndBitangentUnnormalized(snapped_normal);
t = t * (1/world_units_per_luxel);
b = b * (1/world_units_per_luxel);
qmat<float, 3, 3> world_to_lm;
world_to_lm.set_row(0, t);
world_to_lm.set_row(1, b);
world_to_lm.set_row(2, snapped_normal);
aabb2f lm_bounds;
for (int i = 0; i < face.numedges; i++) {
const qvec3f &worldpoint = Face_PointAtIndex(&bsp, &face, i);
const qvec2f lmcoord = world_to_lm * worldpoint;
lm_bounds += lmcoord;
}
qvec2i lm_mins;
for (int i = 0; i < 2; i++) {
lm_bounds[0][i] = floor(lm_bounds[0][i]);
lm_bounds[1][i] = ceil(lm_bounds[1][i]);
lm_mins[i] = static_cast<int>(lm_bounds[0][i]);
lm_extents[i] = static_cast<int>(lm_bounds[1][i] - lm_bounds[0][i]);
}
worldToLMMatrix.set_row(0, qvec4f(world_to_lm.row(0), -lm_mins[0]));
worldToLMMatrix.set_row(1, qvec4f(world_to_lm.row(1), -lm_mins[1]));
worldToLMMatrix.set_row(2, qvec4f(world_to_lm.row(2), 0));
worldToLMMatrix.set_row(3, qvec4f(0, 0, 0, 1));
lmToWorldMatrix = qv::inverse(worldToLMMatrix);
// world <-> tex conversions
worldToTexCoordMatrix = WorldToTexSpace(&bsp, &face);
texCoordToWorldMatrix = TexSpaceToWorld(&bsp, &face);
// bounds
for (int i = 0; i < face.numedges; i++) {
const qvec3f &worldpoint = Face_PointAtIndex(&bsp, &face, i);
bounds += worldpoint;
auto lm = worldToLMMatrix * qvec4f(worldpoint, 1.0f);
#if 0
logging::print("testing world {} -> lm {}\n",
worldpoint,
lm);
#endif
}
// calculate a bounding sphere for the face
qvec3d radius = (bounds.maxs() - bounds.mins()) * 0.5;
origin = bounds.mins() + radius;
this->radius = qv::length(radius);
}
int faceextents_t::width() const
{
return lm_extents[0] + 1;

View File

@ -70,3 +70,15 @@ void bspxbrushes_perbrush::stream_read(std::istream &s)
{
s >= std::tie(bounds, contents, numfaces);
}
// bspx_decoupled_lm_perface
void bspx_decoupled_lm_perface::stream_write(std::ostream &s) const
{
s <= std::tie(lmwidth, lmheight, offset, world_to_lm_space);
}
void bspx_decoupled_lm_perface::stream_read(std::istream &s)
{
s >= std::tie(lmwidth, lmheight, offset, world_to_lm_space);
}

View File

@ -120,16 +120,17 @@ qmat4x4f TexSpaceToWorld(const mbsp_t *bsp, const mface_t *f);
* it doesn't affect bsp complexity (actually, can simplify it a little)*/
constexpr size_t MAXDIMENSION = 255 + 1;
struct world_units_per_luxel_t {};
class faceextents_t
{
private:
public:
qvec2i lm_extents;
qmat4x4f worldToTexCoordMatrix;
qmat4x4f texCoordToWorldMatrix;
qmat4x4f lmToWorldMatrix;
qmat4x4f worldToLMMatrix;
public:
qvec3d origin;
vec_t radius;
aabb3d bounds;
@ -137,6 +138,8 @@ public:
faceextents_t() = default;
faceextents_t(const mface_t &face, const mbsp_t &bsp, float lmshift);
faceextents_t(const mface_t &face, const mbsp_t &bsp, uint16_t lmwidth, uint16_t lmheight, texvecf world_to_lm_space);
faceextents_t(const mface_t &face, const mbsp_t &bsp, world_units_per_luxel_t tag, float world_units_per_luxel);
int width() const;
int height() const;

View File

@ -24,6 +24,7 @@
#include <cstdint>
#include <common/aabb.hh>
#include <memory>
#include <common/bspfile.hh>
/* ========================================================================= */
@ -98,4 +99,22 @@ struct bspxfacenormals_header
uint32_t bitangent;
};
// DECOUPLED_LM BSPX lump (subject to change!)
struct bspx_decoupled_lm_perface
{
uint16_t lmwidth; // pixels
uint16_t lmheight; // pixels
// offset into dlightdata lump.
// start of numstyles (from face struct) * (lmwidth * lmheight) samples
int32_t offset;
// 2 rows * 4 column matrix, stored in row major order
// this is a world -> lightmap space transformation matrix
texvecf world_to_lm_space;
// serialize for streams
void stream_write(std::ostream &s) const;
void stream_read(std::istream &s);
};
// BSPX data

View File

@ -370,6 +370,7 @@ public:
setting_func bspxlux;
setting_func bspxonly;
setting_func bspx;
setting_scalar world_units_per_luxel;
setting_bool litonly;
setting_bool nolights;
setting_int32 facestyles;

View File

@ -52,11 +52,12 @@ std::unordered_map<int, qvec3f> GetDirectLighting(
void SetupDirt(settings::worldspawn_keys &cfg);
float DirtAtPoint(const settings::worldspawn_keys &cfg, raystream_intersection_t *rs, const qvec3d &point,
const qvec3d &normal, const modelinfo_t *selfshadow);
std::unique_ptr<lightsurf_t> CreateLightmapSurface(
const mbsp_t *bsp, const mface_t *face, const facesup_t *facesup, const settings::worldspawn_keys &cfg);
std::unique_ptr<lightsurf_t> CreateLightmapSurface(const mbsp_t *bsp, const mface_t *face, const facesup_t *facesup,
const bspx_decoupled_lm_perface *facesup_decoupled, const settings::worldspawn_keys &cfg);
bool Face_IsLightmapped(const mbsp_t *bsp, const mface_t *face);
void DirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::worldspawn_keys &cfg);
void IndirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::worldspawn_keys &cfg);
void FinishLightmapSurface(const mbsp_t *bsp, lightsurf_t *lightsurf);
void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, lightsurf_t *lightsurf,
const faceextents_t &extents, const faceextents_t &output_extents);
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);

View File

@ -63,6 +63,7 @@ std::vector<std::unique_ptr<lightsurf_t>> &LightSurfaces()
}
static std::vector<facesup_t> faces_sup; // lit2/bspx stuff
static std::vector<bspx_decoupled_lm_perface> facesup_decoupled_global;
bool IsOutputtingSupplementaryData()
{
@ -296,6 +297,7 @@ light_settings::light_settings()
write_luxfile = lightfile::bspx;
},
&experimental_group, "writes both rgb and directions 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"},
nolights{this, "nolights", false, &output_group, "ignore light entities (only sunlight/minlight)"},
facestyles{this, "facestyles", 4, &output_group, "max amount of styles per face; requires BSPX lump if > 4"},
@ -619,6 +621,7 @@ static void CreateLightmapSurfaces(mbsp_t *bsp)
logging::funcheader();
logging::parallel_for(static_cast<size_t>(0), bsp->dfaces.size(), [&bsp](size_t i) {
auto facesup = faces_sup.empty() ? nullptr : &faces_sup[i];
auto facesup_decoupled = facesup_decoupled_global.empty() ? nullptr : &facesup_decoupled_global[i];
auto face = &bsp->dfaces[i];
/* One extra lightmap is allocated to simplify handling overflow */
@ -636,10 +639,14 @@ static void CreateLightmapSurfaces(mbsp_t *bsp)
for (size_t i = 0; i < MAXLIGHTMAPS; i++) {
face->styles[i] = INVALID_LIGHTSTYLE_OLD;
}
if (facesup_decoupled) {
facesup_decoupled->offset = -1;
}
}
}
light_surfaces[i] = CreateLightmapSurface(bsp, face, facesup, light_options);
light_surfaces[i] = CreateLightmapSurface(bsp, face, facesup, facesup_decoupled, light_options);
});
}
@ -658,22 +665,24 @@ static void SaveLightmapSurfaces(mbsp_t *bsp)
auto f = &bsp->dfaces[i];
const modelinfo_t *face_modelinfo = ModelInfoForFace(bsp, i);
if (faces_sup.empty()) {
SaveLightmapSurface(bsp, f, nullptr, surf.get(), surf->extents, surf->extents);
if (!facesup_decoupled_global.empty()) {
SaveLightmapSurface(bsp, f, nullptr, &facesup_decoupled_global[i], surf.get(), surf->extents, surf->extents);
} else if (faces_sup.empty()) {
SaveLightmapSurface(bsp, f, nullptr, nullptr, surf.get(), surf->extents, surf->extents);
} 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], surf.get(), surf->extents, surf->extents);
SaveLightmapSurface(bsp, f, &faces_sup[i], nullptr, surf.get(), surf->extents, surf->extents);
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, surf.get(), surf->extents, surf->vanilla_extents);
SaveLightmapSurface(bsp, f, &faces_sup[i], surf.get(), surf->extents, surf->extents);
SaveLightmapSurface(bsp, f, nullptr, nullptr, surf.get(), surf->extents, surf->vanilla_extents);
SaveLightmapSurface(bsp, f, &faces_sup[i], nullptr, surf.get(), surf->extents, surf->extents);
}
light_surfaces[i].reset();
@ -831,6 +840,12 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
}
}
// decoupled lightmaps
facesup_decoupled_global.clear();
if (light_options.world_units_per_luxel.isChanged()) {
facesup_decoupled_global.resize(bsp.dfaces.size());
}
CalculateVertexNormals(&bsp);
// create lightmap surfaces
@ -896,6 +911,7 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
bspdata->bspx.entries.erase("LMSTYLE16");
bspdata->bspx.entries.erase("LMSTYLE");
bspdata->bspx.entries.erase("LMOFFSET");
bspdata->bspx.entries.erase("DECOUPLED_LM");
if (!faces_sup.empty()) {
bool needoffsets = false;
@ -978,6 +994,20 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
bspdata->bspx.transfer("LMOFFSET", offsets_mem);
}
}
if (!facesup_decoupled_global.empty()) {
std::vector<uint8_t> mem(sizeof(bspx_decoupled_lm_perface) * bsp.dfaces.size());
omemstream stream(mem.data(), mem.size(), std::ios_base::out | std::ios_base::binary);
stream << endianness<std::endian::little>;
for (size_t i = 0; i < bsp.dfaces.size(); i++) {
stream <= facesup_decoupled_global[i];
}
logging::print("DECOUPLED_LM BSPX lump written\n");
bspdata->bspx.transfer("DECOUPLED_LM", mem);
}
}
static void LoadExtendedTexinfoFlags(const fs::path &sourcefilename, const mbsp_t *bsp)

View File

@ -413,8 +413,7 @@ static void CalcPoints(
const vec_t us = starts + s * st_step;
const vec_t ut = startt + t * st_step;
point = surf->extents.LMCoordToWorld(qvec2f(us, ut)) +
surf->plane.normal; // one unit in front of face
point = surf->extents.LMCoordToWorld(qvec2f(us, ut)) + surf->plane.normal; // one unit in front of face
// do this before correcting the point, so we can wrap around the inside of pipes
const bool phongshaded = (surf->curved && cfg.phongallowed.value());
@ -587,7 +586,8 @@ static void CalcPvs(const mbsp_t *bsp, lightsurf_t *lightsurf)
}
static std::unique_ptr<lightsurf_t> Lightsurf_Init(const modelinfo_t *modelinfo, const settings::worldspawn_keys &cfg,
const mface_t *face, const mbsp_t *bsp, const facesup_t *facesup)
const mface_t *face, const mbsp_t *bsp, const facesup_t *facesup,
const bspx_decoupled_lm_perface *facesup_decoupled)
{
auto spaceToWorld = TexSpaceToWorld(bsp, face);
@ -697,7 +697,12 @@ static std::unique_ptr<lightsurf_t> Lightsurf_Init(const modelinfo_t *modelinfo,
lightsurf->tnormal = -qv::normalize(tex->vecs.row(1).xyz());
/* Set up the surface points */
lightsurf->extents = faceextents_t(*face, *bsp, lightsurf->lightmapscale);
if (light_options.world_units_per_luxel.isChanged()) {
lightsurf->extents = faceextents_t(*face, *bsp, world_units_per_luxel_t{},
light_options.world_units_per_luxel.value());
} else {
lightsurf->extents = faceextents_t(*face, *bsp, lightsurf->lightmapscale);
}
lightsurf->vanilla_extents = faceextents_t(*face, *bsp, 16.0);
CalcPoints(modelinfo, modelinfo->offset, lightsurf.get(), bsp, face);
@ -2528,8 +2533,9 @@ static void WriteSingleLightmap(const mbsp_t *bsp, const mface_t *face, const li
}
}
void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, lightsurf_t *lightsurf,
const faceextents_t &extents, const faceextents_t &output_extents)
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)
{
lightmapdict_t &lightmaps = lightsurf->lightmapsByStyle;
const int actual_width = extents.width();
@ -2693,6 +2699,15 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, l
for (; mapnum < MAXLIGHTMAPS; mapnum++) {
face->styles[mapnum] = INVALID_LIGHTSTYLE_OLD;
}
if (facesup_decoupled) {
facesup_decoupled->lmwidth = output_width;
facesup_decoupled->lmheight = output_height;
for (size_t i = 0; i < 2; ++i) {
facesup_decoupled->world_to_lm_space.set_row(i,
output_extents.worldToLMMatrix.row(i));
}
}
}
if (!numstyles)
@ -2714,6 +2729,9 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, l
facesup->lightofs = lightofs;
} else {
face->lightofs = lightofs;
if (facesup_decoupled) {
facesup_decoupled->offset = lightofs;
}
}
// sanity check that we don't save a lightmap for a non-lightmapped face
@ -2741,8 +2759,8 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, l
}
}
std::unique_ptr<lightsurf_t> CreateLightmapSurface(
const mbsp_t *bsp, const mface_t *face, const facesup_t *facesup, const settings::worldspawn_keys &cfg)
std::unique_ptr<lightsurf_t> CreateLightmapSurface(const mbsp_t *bsp, const mface_t *face, const facesup_t *facesup,
const bspx_decoupled_lm_perface *facesup_decoupled, const settings::worldspawn_keys &cfg)
{
/* Find the correct model offset */
const modelinfo_t *modelinfo = ModelInfoForFace(bsp, Face_GetNum(bsp, face));
@ -2767,7 +2785,7 @@ std::unique_ptr<lightsurf_t> CreateLightmapSurface(
if (!Q_strcasecmp(texname, "skip"))
return nullptr;
return Lightsurf_Init(modelinfo, cfg, face, bsp, facesup);
return Lightsurf_Init(modelinfo, cfg, face, bsp, facesup, facesup_decoupled);
}
/*

View File

@ -21,9 +21,6 @@ static void LoadTestmap(const std::filesystem::path &name, std::vector<std::stri
"-path",
wal_metadata_path.string()
};
for (auto &arg : extra_args) {
args.push_back(arg);
}
args.push_back(map_path.string());
args.push_back(bsp_path.string());
@ -36,9 +33,12 @@ static void LoadTestmap(const std::filesystem::path &name, std::vector<std::stri
{
std::vector<std::string> light_args{
"", // the exe path, which we're ignoring in this case
"-extra",
bsp_path.string()
};
for (auto &arg : extra_args) {
light_args.push_back(arg);
}
light_args.push_back(bsp_path.string());
light_main(light_args);
}
@ -56,5 +56,5 @@ static void LoadTestmap(const std::filesystem::path &name, std::vector<std::stri
}
TEST_CASE("TestLight") {
LoadTestmap("q2_lightmap_custom_scale.map", {});
LoadTestmap("q2_lightmap_custom_scale.map", {"-threads", "1", "-extra", "-world_units_per_luxel", "8"});
}