diff --git a/include/qbsp/map.hh b/include/qbsp/map.hh index 38451a37..035befd8 100644 --- a/include/qbsp/map.hh +++ b/include/qbsp/map.hh @@ -367,5 +367,4 @@ void ExportObj_Marksurfaces(const std::string &filesuffix, const node_t *nodes); void WriteBspBrushMap(const fs::path &name, const bspbrush_t::container &list); -bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec); -void TestExpandBrushes(mapentity_t *src); +bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec); \ No newline at end of file diff --git a/include/qbsp/qbsp.hh b/include/qbsp/qbsp.hh index 7b1a2580..97f6e391 100644 --- a/include/qbsp/qbsp.hh +++ b/include/qbsp/qbsp.hh @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -245,6 +246,65 @@ public: std::string format() const override { return "[x [y [z]]]"; } }; +class setting_debugexpand : public setting_value> +{ +public: + inline setting_debugexpand(setting_container *dictionary, const nameset &names, + const setting_group *group = nullptr, const char *description = "") + : setting_value(dictionary, names, {}, group, description) + { + } + + bool parse(const std::string &settingName, parser_base_t &parser, source source) override + { + std::array values; + size_t i = 0; + + try { + for (; i < 6; i++) { + if (!parser.parse_token(PARSE_PEEK)) { + throw std::exception(); + } + + values[i] = std::stod(parser.token); + + parser.parse_token(); + } + + this->setValue(aabb3d { { values[0], values[1], values[2] }, { values[3], values[4], values[5] } }, source); + + return true; + } catch (std::exception &) { + // single hull value + if (i == 1) { + setValue(static_cast(values[0]), source); + return true; + } + + return false; + } + } + + std::string stringValue() const override { return is_hull() ? std::to_string(hull_index_value()) : fmt::format("{}", hull_bounds_value()); } + + std::string format() const override { return "[single hull index] or [mins_x mins_y mins_z maxs_x maxs_y maxs_z]"; } + + inline bool is_hull() const + { + return std::holds_alternative(_value); + } + + inline const uint8_t &hull_index_value() const + { + return std::get(_value); + } + + inline const aabb3d &hull_bounds_value() const + { + return std::get(_value); + } +}; + class qbsp_settings : public common_settings { public: @@ -302,6 +362,7 @@ public: setting_bool outsidedebug{this, "outsidedebug", false, &debugging_group, "write a .map after outside filling showing non-visible brush sides"}; setting_bool debugchop{this, "debugchop", false, &debugging_group, "write a .map after ChopBrushes"}; + setting_debugexpand debugexpand{this, "debugexpand", &debugging_group, "write expanded hull .map for debugging/inspecting hulls/brush bevelling"}; setting_bool keepprt{this, "keepprt", false, &debugging_group, "avoid deleting the .prt file on leaking maps"}; setting_bool includeskip{this, "includeskip", false, &common_format_group, "don't cull skip faces from the list of renderable surfaces (Q2RTX)"}; @@ -328,8 +389,6 @@ public: "func_detail_illusionary brushes are omitted from the compile"}; setting_bool omitdetailfence{this, "omitdetailfence", false, &map_development_group, "func_detail_fence brushes are omitted from the compile"}; - setting_bool expand{ - this, "expand", false, &common_format_group, "write hull 1 expanded brushes to expanded.map for debugging"}; setting_wadpathset wadpaths{this, {"wadpath", "xwadpath"}, &map_development_group, "add a path to the wad search paths; wads found in xwadpath's will not be embedded, otherwise they will be embedded (if not -notex)"}; setting_bool notriggermodels{this, "notriggermodels", false, &common_format_group, diff --git a/qbsp/brush.cc b/qbsp/brush.cc index ea803d5f..9d8630a6 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -276,15 +276,9 @@ bool CreateBrushWindings(bspbrush_t *brush) return brush->update_bounds(true); } +#define QBSP3 + #ifndef QBSP3 -struct hullbrush_t { - bspbrush_t &brush; - - std::vector points; - std::vector corners; - std::vector> edges; -}; - /* ============================================================================== @@ -294,30 +288,35 @@ This is done by brute force, and could easily get a lot faster if anyone cares. ============================================================================== */ +struct hullbrush_t { + bspbrush_t &brush; + + std::vector points; + std::vector corners; + std::vector> edges; +}; + /* ============ AddBrushPlane ============= */ -static void -AddBrushPlane(hullbrush_t &hullbrush, const qbsp_plane_t &plane) +static bool AddBrushPlane(hullbrush_t &hullbrush, const qbsp_plane_t &plane) { vec_t len = qv::length(plane.get_normal()); - if (len < 1.0 - NORMAL_EPSILON || len > 1.0 + NORMAL_EPSILON) - Error("%s: invalid normal (vector length %.4f)", __func__, len); for (auto &s : hullbrush.brush.sides) { if (qv::epsilonEqual(s.get_plane(), plane)) { - return; + return false; } } auto &s = hullbrush.brush.sides.emplace_back(); s.planenum = map.add_or_find_plane(plane); s.texinfo = 0; + return true; } - /* ============ TestAddPlane @@ -326,48 +325,41 @@ Adds the given plane to the brush description if all of the original brush vertexes can be put on the front side ============= */ -static void -TestAddPlane(hullbrush_t &hullbrush, qbsp_plane_t plane) +static bool TestAddPlane(hullbrush_t &hullbrush, const qbsp_plane_t &plane) { - int i, c; - vec_t d; - qvec3d *corner; - qbsp_plane_t flip; - bool points_front, points_back; - /* see if the plane has already been added */ for (auto &s : hullbrush.brush.sides) { - if (qv::epsilonEqual(plane, s.get_plane())) - return; - if (qv::epsilonEqual(-plane, s.get_plane())) - return; + if (qv::epsilonEqual(plane, s.get_plane()) || + qv::epsilonEqual(plane, s.get_positive_plane())) { + return false; + } } /* check all the corner points */ - points_front = false; - points_back = false; + bool points_front = false; + bool points_back = false; - corner = &hullbrush.corners.front(); - c = hullbrush.points.size() * 8; + for (size_t i = 0; i < hullbrush.corners.size(); i++) { + vec_t d = qv::dot(hullbrush.corners[i], plane.get_normal()) - plane.get_dist(); - for (i = 0; i < c; i++, corner++) { - d = qv::dot(*corner, plane.get_normal()) - plane.get_dist(); if (d < -qbsp_options.epsilon.value()) { - if (points_front) - return; + if (points_front) { + return false; + } points_back = true; } else if (d > qbsp_options.epsilon.value()) { - if (points_back) - return; + if (points_back) { + return false; + } points_front = true; } } // the plane is a seperator if (points_front) { - AddBrushPlane(hullbrush, -plane); + return AddBrushPlane(hullbrush, -plane); } else { - AddBrushPlane(hullbrush, plane); + return AddBrushPlane(hullbrush, plane); } } @@ -378,29 +370,25 @@ AddHullPoint Doesn't add if duplicated ============= */ -static size_t -AddHullPoint(hullbrush_t &hullbrush, const qvec3d &p, const aabb3d &hull_size) +static size_t AddHullPoint(hullbrush_t &hullbrush, const qvec3d &p, const aabb3d &hull_size) { - size_t i; - int x, y, z; - - for (i = 0; i < hullbrush.points.size(); i++) - if (qv::epsilonEqual(p, hullbrush.points[i], EQUAL_EPSILON)) - return i; + for (auto &pt : hullbrush.points) { + if (qv::epsilonEqual(p, pt, EQUAL_EPSILON)) { + return &pt - hullbrush.points.data(); + } + } hullbrush.points.emplace_back(p); - for (x = 0; x < 2; x++) - for (y = 0; y < 2; y++) - for (z = 0; z < 2; z++) { - qvec3d c; - c[0] = p[0] + hull_size[x][0]; - c[1] = p[1] + hull_size[y][1]; - c[2] = p[2] + hull_size[z][2]; - hullbrush.corners.emplace_back(c); + for (size_t x = 0; x < 2; x++) { + for (size_t y = 0; y < 2; y++) { + for (size_t z = 0; z < 2; z++) { + hullbrush.corners.emplace_back(p + qvec3d { hull_size[x][0], hull_size[y][1], hull_size[z][2] }); } + } + } - return i; + return hullbrush.points.size() - 1; } @@ -408,121 +396,120 @@ AddHullPoint(hullbrush_t &hullbrush, const qvec3d &p, const aabb3d &hull_size) ============ AddHullEdge -Creates all of the hull planes around the given edge, if not done allready +Creates all of the hull planes around the given edge, if not done already ============= */ -static void -AddHullEdge(hullbrush_t &hullbrush, const qvec3d &p1, const qvec3d &p2, const aabb3d &hull_size) +static bool AddHullEdge(hullbrush_t &hullbrush, const qvec3d &p1, const qvec3d &p2, const aabb3d &hull_size) { - size_t pt1, pt2; - int i; - int a, b, c, d, e; - qvec3d edgevec, planeorg, planevec; - qplane3d plane; - vec_t length; + std::array edge = { + AddHullPoint(hullbrush, p1, hull_size), + AddHullPoint(hullbrush, p2, hull_size) + }; - pt1 = AddHullPoint(hullbrush, p1, hull_size); - pt2 = AddHullPoint(hullbrush, p2, hull_size); + for (auto &e : hullbrush.edges) { + if (e == edge || e == decltype(edge) { edge[1], edge[0] }) { + return false; + } + } - for (i = 0; i < hullbrush.edges.size(); i++) - if ((hullbrush.edges[i][0] == pt1 && hullbrush.edges[i][1] == pt2) - || (hullbrush.edges[i][0] == pt2 && hullbrush.edges[i][1] == pt1)) - return; + hullbrush.edges.emplace_back(edge); - hullbrush.edges.push_back({ pt1, pt2 }); - - edgevec = p1 - p2; - qv::normalizeInPlace(edgevec); - - for (a = 0; a < 3; a++) { - b = (a + 1) % 3; - c = (a + 2) % 3; + qvec3d edgevec = qv::normalize(p1 - p2); + bool added = false; + for (size_t a = 0; a < 3; a++) { + qvec3d planevec{}; planevec[a] = 1; - planevec[b] = 0; - planevec[c] = 0; + + qplane3d plane; plane.normal = qv::cross(planevec, edgevec); - length = qv::normalizeInPlace(plane.normal); + + vec_t length = qv::normalizeInPlace(plane.normal); /* If this edge is almost parallel to the hull edge, skip it. */ - if (length < ANGLEEPSILON) + if (length < ANGLEEPSILON) { continue; + } - for (d = 0; d <= 1; d++) { - for (e = 0; e <= 1; e++) { - planeorg = p1; + size_t b = (a + 1) % 3; + size_t c = (a + 2) % 3; + + for (size_t d = 0; d < 2; d++) { + for (size_t e = 0; e < 2; e++) { + qvec3d planeorg = p1; planeorg[b] += hull_size[d][b]; planeorg[c] += hull_size[e][c]; plane.dist = qv::dot(planeorg, plane.normal); - TestAddPlane(hullbrush, plane); + added = TestAddPlane(hullbrush, plane) || added; } } } -} + return added; +} /* ============ ExpandBrush ============= */ -static void -ExpandBrush(hullbrush_t &hullbrush, const aabb3d &hull_size) +static void ExpandBrush(hullbrush_t &hullbrush, const aabb3d &hull_size) { - int i, x, s; - qvec3d corner; - qplane3d plane; - int cBevEdge = 0; - size_t total_original_sides = hullbrush.brush.sides.size(); // create all the hull points for (auto &f : hullbrush.brush.sides) { - if (!f.w) { - FError("bad input winding"); - } - for (i = 0; i < f.w.size(); i++) { - AddHullPoint(hullbrush, f.w[i], hull_size); - cBevEdge++; + for (auto &pt : f.w) { + AddHullPoint(hullbrush, pt, hull_size); } } // expand all of the planes for (auto &f : hullbrush.brush.sides) { - if (f.get_texinfo().flags.no_expand) + if (f.get_texinfo().flags.no_expand) { continue; - corner = {}; - plane = f.get_plane(); - for (x = 0; x < 3; x++) { - if (plane.normal[x] > 0) + } + qvec3d corner = {}; + qplane3d plane = f.get_plane(); + for (size_t x = 0; x < 3; x++) { + if (plane.normal[x] > 0) { corner[x] = hull_size[1][x]; - else if (plane.normal[x] < 0) + } else if (plane.normal[x] < 0) { corner[x] = hull_size[0][x]; + } } plane.dist += qv::dot(corner, plane.normal); f.planenum = map.add_or_find_plane(plane); } // add any axis planes not contained in the brush to bevel off corners - for (x = 0; x < 3; x++) - for (s = -1; s <= 1; s += 2) { + for (size_t x = 0; x < 3; x++) { + for (int32_t s = -1; s <= 1; s += 2) { // add the plane + qplane3d plane; plane.normal = {}; - plane.normal[x] = (vec_t)s; - if (s == -1) + plane.normal[x] = (vec_t) s; + if (s == -1) { plane.dist = -hullbrush.brush.bounds.mins()[x] + -hull_size[0][x]; - else + } else { plane.dist = hullbrush.brush.bounds.maxs()[x] + hull_size[1][x]; + } AddBrushPlane(hullbrush, plane); } + } // add all of the edge bevels - for (size_t f = 0; f < total_original_sides; f++) { - auto &side = hullbrush.brush.sides[f]; + for (size_t f = 0; f < hullbrush.brush.sides.size(); f++) { + auto *side = &hullbrush.brush.sides[f]; + auto *w = &side->w; - for (i = 0; i < side.w.size(); i++) - AddHullEdge(hullbrush, side.w[i], - side.w[(i + 1) % side.w.size()], hull_size); + for (size_t i = 0; i < w->size(); i++) { + if (AddHullEdge(hullbrush, (*w)[i], (*w)[(i + 1) % w->size()], hull_size)) { + // re-fetch ptrs + side = &hullbrush.brush.sides[f]; + w = &side->w; + } + } } } #endif diff --git a/qbsp/map.cc b/qbsp/map.cc index f45fed0d..785dc6b3 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -1638,6 +1638,9 @@ static std::optional ParseBrushFace(parser_t &parser, const mapbrush_ return face; } +#define QBSP3 + +#ifdef QBSP3 /* ================= AddBrushBevels @@ -1738,11 +1741,22 @@ inline void AddBrushBevels(mapentity_t &e, mapbrush_t &b) qplane3d plane {}; plane.normal[axis] = dir; plane.normal = qv::cross(vec, plane.normal); - if (qv::normalizeInPlace(plane.normal) < 0.5) { + + // If this edge is almost parallel to the hull edge, skip it + if (qv::normalizeInPlace(plane.normal) < ANGLEEPSILON) { continue; } plane.dist = qv::dot(b.faces[i].winding[j], plane.normal); + auto w = BaseWindingForPlane(plane); + + if (fabs(trunc(w[0][0])) == 693 || + fabs(trunc(w[1][0])) == 693 || + fabs(trunc(w[2][0])) == 693) { + __debugbreak(); + } + + // if all the points on all the sides are // behind this plane, it is a proper edge bevel for (k = 0; k < b.faces.size(); k++) { @@ -1792,6 +1806,267 @@ inline void AddBrushBevels(mapentity_t &e, mapbrush_t &b) } } } +#else +/* +============================================================================== + +BEVELED CLIPPING HULL GENERATION + +This is done by brute force, and could easily get a lot faster if anyone cares. +============================================================================== +*/ + +struct map_hullbrush_t { + mapentity_t &entity; + mapbrush_t &brush; + + std::vector points; + std::vector corners; + std::vector> edges; +}; + +/* +============ +AddBrushPlane +============= +*/ +static bool AddBrushPlane(map_hullbrush_t &hullbrush, const qbsp_plane_t &plane, size_t &index) +{ + for (auto &s : hullbrush.brush.faces) { + if (qv::epsilonEqual(s.get_plane(), plane)) { + index = &s - hullbrush.brush.faces.data(); + return false; + } + } + + index = hullbrush.brush.faces.size(); + auto &s = hullbrush.brush.faces.emplace_back(); + s.planenum = map.add_or_find_plane(plane); + // add this plane + s.texinfo = hullbrush.brush.faces[0].texinfo; + s.contents = hullbrush.brush.faces[0].contents; + // fixme: why did we need to store all this stuff again, isn't + // it in texinfo? + s.raw_info = hullbrush.brush.faces[0].raw_info; + s.flags = hullbrush.brush.faces[0].flags; + s.texname = hullbrush.brush.faces[0].texname; + s.value = hullbrush.brush.faces[0].value; + s.bevel = true; + return true; +} + +/* +============ +TestAddPlane + +Adds the given plane to the brush description if all of the original brush +vertexes can be put on the front side +============= +*/ +static bool TestAddPlane(map_hullbrush_t &hullbrush, const qbsp_plane_t &plane) +{ + /* see if the plane has already been added */ + for (auto &s : hullbrush.brush.faces) { + if (qv::epsilonEqual(plane, s.get_plane()) || + qv::epsilonEqual(plane, s.get_positive_plane())) { + return false; + } + } + + /* check all the corner points */ + bool points_front = false; + bool points_back = false; + + for (size_t i = 0; i < hullbrush.corners.size(); i++) { + vec_t d = qv::dot(hullbrush.corners[i], plane.get_normal()) - plane.get_dist(); + + if (d < -qbsp_options.epsilon.value()) { + if (points_front) { + return false; + } + points_back = true; + } else if (d > qbsp_options.epsilon.value()) { + if (points_back) { + return false; + } + points_front = true; + } + } + + bool added; + size_t index; + + // the plane is a seperator + if (points_front) { + added = AddBrushPlane(hullbrush, -plane, index); + } else { + added = AddBrushPlane(hullbrush, plane, index); + } + + if (added) { + hullbrush.entity.numedgebevels++; + } + + return added; +} + +/* +============ +AddHullPoint + +Doesn't add if duplicated +============= +*/ +static size_t AddHullPoint(map_hullbrush_t &hullbrush, const qvec3d &p, const aabb3d &hull_size) +{ + for (auto &pt : hullbrush.points) { + if (qv::epsilonEqual(p, pt, EQUAL_EPSILON)) { + return &pt - hullbrush.points.data(); + } + } + + hullbrush.points.emplace_back(p); + + for (size_t x = 0; x < 2; x++) { + for (size_t y = 0; y < 2; y++) { + for (size_t z = 0; z < 2; z++) { + hullbrush.corners.emplace_back(p + qvec3d { hull_size[x][0], hull_size[y][1], hull_size[z][2] }); + } + } + } + + return hullbrush.points.size() - 1; +} + + +/* +============ +AddHullEdge + +Creates all of the hull planes around the given edge, if not done already +============= +*/ +static bool AddHullEdge(map_hullbrush_t &hullbrush, const qvec3d &p1, const qvec3d &p2, const aabb3d &hull_size) +{ + std::array edge = { + AddHullPoint(hullbrush, p1, hull_size), + AddHullPoint(hullbrush, p2, hull_size) + }; + + for (auto &e : hullbrush.edges) { + if (e == edge || e == decltype(edge) { edge[1], edge[0] }) { + return false; + } + } + + hullbrush.edges.emplace_back(edge); + + qvec3d edgevec = qv::normalize(p1 - p2); + bool added = false; + + for (size_t a = 0; a < 3; a++) { + qvec3d planevec{}; + planevec[a] = 1; + + qplane3d plane; + plane.normal = qv::cross(planevec, edgevec); + + vec_t length = qv::normalizeInPlace(plane.normal); + + /* If this edge is almost parallel to the hull edge, skip it. */ + if (length < ANGLEEPSILON) { + continue; + } + + size_t b = (a + 1) % 3; + size_t c = (a + 2) % 3; + + for (size_t d = 0; d < 2; d++) { + for (size_t e = 0; e < 2; e++) { + qvec3d planeorg = p1; + planeorg[b] += hull_size[d][b]; + planeorg[c] += hull_size[e][c]; + plane.dist = qv::dot(planeorg, plane.normal); + added = TestAddPlane(hullbrush, plane) || added; + } + } + } + + return added; +} + +/* +============ +ExpandBrush +============= +*/ +static void ExpandBrush(map_hullbrush_t &hullbrush, const aabb3d &hull_size) +{ + size_t total_original_sides = hullbrush.brush.faces.size(); + + // create all the hull points + for (auto &f : hullbrush.brush.faces) { + for (auto &pt : f.winding) { + AddHullPoint(hullbrush, pt, hull_size); + } + } + + // expand all of the planes + for (auto &f : hullbrush.brush.faces) { + /*if (f.get_texinfo().flags.no_expand) { + continue; + }*/ + qvec3d corner = {}; + qplane3d plane = f.get_plane(); + for (size_t x = 0; x < 3; x++) { + if (plane.normal[x] > 0) { + corner[x] = hull_size[1][x]; + } else if (plane.normal[x] < 0) { + corner[x] = hull_size[0][x]; + } + } + plane.dist += qv::dot(corner, plane.normal); + f.planenum = map.add_or_find_plane(plane); + } + + // add any axis planes not contained in the brush to bevel off corners + for (size_t x = 0, o = 0; x < 3; x++) { + for (int32_t s = -1; s <= 1; s += 2, o++) { + // add the plane + qplane3d plane; + plane.normal = {}; + plane.normal[x] = (vec_t) s; + if (s == -1) { + plane.dist = -hullbrush.brush.bounds.mins()[x] + -hull_size[0][x]; + } else { + plane.dist = hullbrush.brush.bounds.maxs()[x] + hull_size[1][x]; + } + + size_t index; + AddBrushPlane(hullbrush, plane, index); + + // if the plane is not in it canonical order, swap it + if (index != o) { + std::swap(hullbrush.brush.faces[o], hullbrush.brush.faces[index]); + } + } + } + + // add all of the edge bevels + for (size_t f = 0; f < hullbrush.brush.faces.size(); f++) { + auto *side = &hullbrush.brush.faces[f]; + auto *w = &side->winding; + + for (size_t i = 0; i < w->size(); i++) { + if (AddHullEdge(hullbrush, (*w)[i], (*w)[(i + 1) % w->size()], hull_size)) { + // re-fetch ptrs + side = &hullbrush.brush.faces[f]; + w = &side->winding; + } + } + } +} +#endif static contentflags_t Brush_GetContents(const mapbrush_t &mapbrush) { @@ -2260,6 +2535,63 @@ inline bool MapBrush_IsHint(const mapbrush_t &brush) return false; } +/* +================== +WriteBspBrushMap + +from q3map +================== +*/ +inline void WriteMapBrushMap(const fs::path &name, const std::vector &list, const aabb3d &hull) +{ + logging::print("writing {}\n", name); + std::ofstream f(name); + + if (!f) + FError("Can't write {}", name); + + fmt::print(f, "{{\n\"classname\" \"worldspawn\"\n"); + + for (auto &brush : list) { + fmt::print(f, "{{\n"); + for (auto &face : brush.faces) { + + qvec3d corner = {}; + qplane3d plane = face.get_plane(); + for (size_t x = 0; x < 3; x++) { + if (plane.normal[x] > 0) { + corner[x] = hull[1][x]; + } else if (plane.normal[x] < 0) { + corner[x] = hull[0][x]; + } + } + plane.dist += qv::dot(corner, plane.normal); + + winding_t w = BaseWindingForPlane(plane); + + fmt::print(f, "( {} ) ", w[0]); + fmt::print(f, "( {} ) ", w[1]); + fmt::print(f, "( {} ) ", w[2]); + +#if 0 + if (face.visible) { + fmt::print(f, "skip 0 0 0 1 1\n"); + } else { + fmt::print(f, "nonvisible 0 0 0 1 1\n"); + } +#endif + + fmt::print(f, "{} 0 0 0 1 1\n", face.texname); + } + + fmt::print(f, "}}\n"); + } + + fmt::print(f, "}}\n"); + + f.close(); +} + void ProcessMapBrushes() { logging::funcheader(); @@ -2334,7 +2666,14 @@ void ProcessMapBrushes() num_faces += old_num_faces; // add the brush bevels +#ifdef QBSP3 AddBrushBevels(entity, brush); +#else + { + map_hullbrush_t hullbrush { entity, brush }; + ExpandBrush(hullbrush, { { 0, 0, 0 }, { 0, 0, 0 } }); + } +#endif for (auto &f : brush.faces) { f.lmshift = brush.lmshift; @@ -2418,6 +2757,24 @@ void ProcessMapBrushes() logging::print(logging::flag::STAT, " {:8} brushes translated from origins\n", num_offset); } logging::print(logging::flag::STAT, "\n"); + + if (qbsp_options.debugexpand.isChanged()) { + aabb3d hull; + + if (qbsp_options.debugexpand.is_hull()) { + const auto &hulls = qbsp_options.target_game->get_hull_sizes(); + + if (hulls.size() <= qbsp_options.debugexpand.hull_index_value()) { + FError("invalid hull index passed to debugexpand\n"); + } + + hull = *(hulls.begin() + qbsp_options.debugexpand.hull_index_value()); + } else { + hull = qbsp_options.debugexpand.hull_bounds_value(); + } + + WriteMapBrushMap("expanded.map", map.world_entity()->mapbrushes, hull); + } } void LoadMapFile(void) @@ -2847,29 +3204,3 @@ void WriteBspBrushMap(const fs::path &name, const bspbrush_t::container &list) f.close(); } - -/* -================ -TestExpandBrushes - -Expands all the brush planes and saves a new map out to -allow visual inspection of the clipping bevels - -from q3map -================ -*/ -static void TestExpandBrushes(mapentity_t *src) -{ - bspbrush_t::container hull1brushes; - - for (auto &mapbrush : src->mapbrushes) { - auto hull1brush = LoadBrush(src, &mapbrush, {CONTENTS_SOLID}, - qbsp_options.target_game->id == GAME_QUAKE_II ? std::nullopt : std::optional(1), std::nullopt); - - if (hull1brush) { - hull1brushes.emplace_back(bspbrush_t::make_ptr(std::move(*hull1brush))); - } - } - - WriteBspBrushMap("expanded.map", hull1brushes); -} diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index 839d76de..d3c2fc06 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -953,10 +953,6 @@ void ProcessFile() // handle load time operation on the .map ProcessMapBrushes(); - if (qbsp_options.expand.value()) { - TestExpandBrushes(map.world_entity()); - } - // initialize secondary textures LoadSecondaryTextures();