From d36e2f5114eccbccb1882ae6af58b663afb3ccc7 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Mon, 12 Jun 2023 15:23:47 -0400 Subject: [PATCH] --scale option for BSPUtil to do a post-process scale --- bsputil/bsputil.cc | 155 ++++++++++++++++++++++++++++++++++++++++++++- qbsp/portals.cc | 12 ++-- qbsp/writebsp.cc | 4 +- 3 files changed, 160 insertions(+), 11 deletions(-) diff --git a/bsputil/bsputil.cc b/bsputil/bsputil.cc index 966e46fe..046dd71c 100644 --- a/bsputil/bsputil.cc +++ b/bsputil/bsputil.cc @@ -603,8 +603,159 @@ int bsputil_main(int argc, char **argv) map_file = LoadMapOrEntFile(source); } - for (int32_t i = 0; i < argc - 1; i++) { - if (!strcmp(argv[i], "--replace-entities")) { + for (int32_t i = 1; i < argc - 1; i++) { + if (!strcmp(argv[i], "--scale")) { + + i++; + if (i == argc - 1) { + Error("--scale requires two arguments"); + } + + fmt::print("scaling {} by {}\n", source, argv[i]); + + double scalar = atof(argv[i]); + + mbsp_t &bsp = std::get(bspdata.bsp); + + // adjust entity origins + { + auto ents = EntData_Parse(bsp); + + for (auto &ent : ents) { + if (ent.has("origin")) { + qvec3d origin; + ent.get_vector("origin", origin); + origin *= scalar; + ent.set("origin", fmt::format("{} {} {}", origin[0], origin[1], origin[2])); + } + } + + bsp.dentdata = EntData_Write(ents); + } + + // adjust vertices + for (auto &v : bsp.dvertexes) { + v *= scalar; + } + + // adjust planes + for (auto &p : bsp.dplanes) { + p.dist *= scalar; + } + + // adjust node/leaf/model bounds + for (auto &m : bsp.dmodels) { + m.origin *= scalar; + m.mins *= scalar; + m.maxs *= scalar; + } + + for (auto &l : bsp.dleafs) { + l.mins *= scalar; + l.maxs *= scalar; + } + + for (auto &m : bsp.dnodes) { + m.mins *= scalar; + m.maxs *= scalar; + } + + auto scaleTexInfo = [&](mtexinfo_t &t) + { + // update texinfo + + const qmat3x3d inversescaleM{// column-major... + 1 / scalar, 0.0, 0.0, 0.0, 1 / scalar, 0.0, 0.0, 0.0, 1 / scalar}; + + auto &texvecs = t.vecs; + texvecf newtexvecs; + + for (int i = 0; i < 2; i++) { + const qvec4f in = texvecs.row(i); + const qvec3f in_first3(in); + + const qvec3f out_first3 = inversescaleM * in_first3; + newtexvecs.set_row(i, {out_first3[0], out_first3[1], out_first3[2], in[3]}); + } + + texvecs = newtexvecs; + }; + + // adjust texinfo + for (auto &t : bsp.texinfo) { + scaleTexInfo(t); + } + + // adjust decoupled LM + if (bspdata.bspx.entries.contains("DECOUPLED_LM")) { + + auto &lump_bytes = bspdata.bspx.entries.at("DECOUPLED_LM"); + + auto istream = imemstream(lump_bytes.data(), lump_bytes.size()); + auto ostream = omemstream(lump_bytes.data(), lump_bytes.size()); + + istream >> endianness; + ostream << endianness; + + bspx_decoupled_lm_perface result; + + for (auto &face : bsp.dfaces) { + istream >= result; + + const qmat3x3d inversescaleM{// column-major... + 1 / scalar, 0.0, 0.0, 0.0, 1 / scalar, 0.0, 0.0, 0.0, 1 / scalar}; + + auto &texvecs = result.world_to_lm_space; + texvecf newtexvecs; + + for (int i = 0; i < 2; i++) { + const qvec4f in = texvecs.row(i); + const qvec3f in_first3(in); + + const qvec3f out_first3 = inversescaleM * in_first3; + newtexvecs.set_row(i, {out_first3[0], out_first3[1], out_first3[2], in[3]}); + } + + texvecs = newtexvecs; + + ostream <= result; + } + } + + // adjust lightgrid + if (bspdata.bspx.entries.contains("LIGHTGRID_OCTREE")) { + + auto &lump_bytes = bspdata.bspx.entries.at("LIGHTGRID_OCTREE"); + + auto istream = imemstream(lump_bytes.data(), lump_bytes.size()); + auto ostream = omemstream(lump_bytes.data(), lump_bytes.size()); + + istream >> endianness; + ostream << endianness; + + { + qvec3f grid_dist; + istream >= grid_dist; + grid_dist *= scalar; + ostream <= grid_dist; + } + + istream.seekg(sizeof(qvec3i), std::ios_base::cur); + ostream.seekp(sizeof(qvec3i), std::ios_base::cur); + + { + qvec3f grid_mins; + istream >= grid_mins; + grid_mins *= scalar; + ostream <= grid_mins; + } + } + + ConvertBSPFormat(&bspdata, bspdata.loadversion); + + WriteBSPFile(source.replace_filename(source.stem().string() + "-scaled.bsp"), &bspdata); + + } else if (!strcmp(argv[i], "--replace-entities")) { i++; if (i == argc - 1) { Error("--replace-entities requires two arguments"); diff --git a/qbsp/portals.cc b/qbsp/portals.cc index f7c33593..72475062 100644 --- a/qbsp/portals.cc +++ b/qbsp/portals.cc @@ -919,13 +919,11 @@ void EmitAreaPortals(node_t *headnode) map.bsp.dareas.emplace_back(); // don't do anything else if we've leaked - if (map.leakfile) { - map.bsp.dareas.emplace_back(); - return; - } - - if (map.antiregions.size() || map.region) { - map.bsp.dareas.emplace_back(); + if (map.leakfile || map.antiregions.size() || map.region) { + for (auto &e : map.entities) { + e.areaportalnum = 0; + e.epairs.remove("style"); + } return; } diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index 8d4e5a05..46467a2d 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -196,8 +196,8 @@ static void ExportLeaf(node_t *node) if (dleaf.contents & Q2_CONTENTS_SOLID) { dleaf.area = AREA_INVALID; } else { - if (map.leakfile) { - dleaf.area = 1; + if (map.leakfile || map.region || map.antiregions.size()) { + dleaf.area = 0; } else { dleaf.area = node->area; }