diff --git a/include/qbsp/brush.hh b/include/qbsp/brush.hh index 30b4938e..fa74a423 100644 --- a/include/qbsp/brush.hh +++ b/include/qbsp/brush.hh @@ -22,13 +22,13 @@ #pragma once #include -#include #include #include class mapentity_t; struct maptexinfo_t; struct mapface_t; +struct qbsp_plane_t; struct side_t { @@ -51,11 +51,19 @@ class mapbrush_t; struct bspbrush_t { + using ptr = std::shared_ptr; + using container = std::vector; + + template + static inline ptr make_ptr(Args&& ...args) + { + return std::make_shared(std::forward(args)...); + } + /** * The brushes in main brush vectors are considered originals. Brush fragments created during * the BrushBSP will have this pointing back to the original brush in the list. */ - bspbrush_t *original; mapbrush_t *mapbrush; aabb3d bounds; int side, testside; // side of node during construction @@ -67,10 +75,8 @@ struct bspbrush_t bool update_bounds(bool warn_on_failures); - std::unique_ptr copy_unique() const; + ptr copy_unique() const; }; -using bspbrush_vector_t = std::vector>; - std::optional LoadBrush(const mapentity_t *src, mapbrush_t *mapbrush, const contentflags_t &contents, const int hullnum); bool CreateBrushWindings(bspbrush_t *brush); \ No newline at end of file diff --git a/include/qbsp/brushbsp.hh b/include/qbsp/brushbsp.hh index 0d1049d2..26fe7f46 100644 --- a/include/qbsp/brushbsp.hh +++ b/include/qbsp/brushbsp.hh @@ -39,5 +39,5 @@ struct tree_t; constexpr vec_t EDGE_LENGTH_EPSILON = 0.2; bool WindingIsTiny(const winding_t &w, double size = EDGE_LENGTH_EPSILON); -std::unique_ptr BrushFromBounds(const aabb3d &bounds); -std::unique_ptr BrushBSP(mapentity_t *entity, const bspbrush_vector_t &brushes, std::optional forced_quick_tree); +bspbrush_t::ptr BrushFromBounds(const aabb3d &bounds); +std::unique_ptr BrushBSP(mapentity_t *entity, const bspbrush_t::container &brushes, std::optional forced_quick_tree); diff --git a/include/qbsp/csg.hh b/include/qbsp/csg.hh index 999ad6f7..ca592cd6 100644 --- a/include/qbsp/csg.hh +++ b/include/qbsp/csg.hh @@ -37,4 +37,3 @@ std::unique_ptr CopyFace(const face_t *in); std::tuple, std::unique_ptr> SplitFace( std::unique_ptr in, const qplane3d &split); void UpdateFaceSphere(face_t *in); -bspbrush_vector_t MakeBspBrushList(const bspbrush_vector_t &brushes); diff --git a/include/qbsp/map.hh b/include/qbsp/map.hh index 62433f07..c4494f00 100644 --- a/include/qbsp/map.hh +++ b/include/qbsp/map.hh @@ -67,8 +67,9 @@ struct mapface_t const texvecf &get_texvecs() const; void set_texvecs(const texvecf &vecs); - + const qbsp_plane_t &get_plane() const; + const qbsp_plane_t &get_positive_plane() const; }; enum class brushformat_t @@ -344,7 +345,7 @@ qvec3d FixRotateOrigin(mapentity_t *entity); constexpr int HULL_COLLISION = -1; /* Create BSP brushes from map brushes */ -void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_vector_t &brushes); +void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_t::container &brushes); std::list CSGFace( face_t *srcface, const mapentity_t *srcentity, const bspbrush_t *srcbrush, const node_t *srcnode); @@ -366,6 +367,6 @@ void ExportObj_Brushes(const std::string &filesuffix, const std::vector> &list); +void WriteBspBrushMap(const fs::path &name, const bspbrush_t::container &list); bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec); diff --git a/include/qbsp/outside.hh b/include/qbsp/outside.hh index 52dac84b..e49b67e9 100644 --- a/include/qbsp/outside.hh +++ b/include/qbsp/outside.hh @@ -28,7 +28,7 @@ class mapentity_t; struct node_t; struct tree_t; -bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes); +bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_t::container &brushes); std::vector FindOccupiedClusters(node_t *headnode); -void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes); +void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_t::container &brushes); diff --git a/include/qbsp/portals.hh b/include/qbsp/portals.hh index a755bafd..93cf54c0 100644 --- a/include/qbsp/portals.hh +++ b/include/qbsp/portals.hh @@ -40,8 +40,8 @@ struct portal_t std::unique_ptr winding; bool sidefound; // false if ->side hasn't been checked - side_t *sides[2]; // [0] = the brush side visible on nodes[0] - it could come from a brush in nodes[1]. NULL = - // non-visible + mapface_t *sides[2]; // [0] = the brush side visible on nodes[0] - it could come from a brush in nodes[1]. NULL = + // non-visible face_t *face[2]; // output face in bsp file }; @@ -78,4 +78,4 @@ std::list> MakeHeadnodePortals(tree_t *tree); void MakePortalsFromBuildportals(tree_t *tree, std::list> buildportals); void EmitAreaPortals(node_t *headnode); void FloodAreas(mapentity_t *entity, node_t *headnode); -void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_vector_t &brushes); +void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_t::container &brushes); diff --git a/include/qbsp/qbsp.hh b/include/qbsp/qbsp.hh index f1939601..50ef77b3 100644 --- a/include/qbsp/qbsp.hh +++ b/include/qbsp/qbsp.hh @@ -48,6 +48,7 @@ #include #include #include +#include enum texcoord_style_t { @@ -633,7 +634,7 @@ struct node_t aabb3d bounds; // bounding volume, not just points inside node_t *parent; // this is also a bounding volume like `bounds` - std::unique_ptr volume; // one for each leaf/node + bspbrush_t::ptr volume; // one for each leaf/node bool is_leaf = false; // information for decision nodes @@ -662,7 +663,7 @@ struct node_t uint32_t firstleafbrush; // Q2 uint32_t numleafbrushes; int32_t area; - std::vector original_brushes; + std::vector original_brushes; }; void InitQBSP(int argc, const char **argv); diff --git a/qbsp/brush.cc b/qbsp/brush.cc index 41d862ab..d4640282 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -40,14 +40,12 @@ const qbsp_plane_t &side_t::get_plane() const const qbsp_plane_t &side_t::get_positive_plane() const { - auto &p = map.get_plane(planenum & ~1); - Q_assert(p.get_normal()[(int) p.get_type() % 3] > 0); - return p; + return map.get_plane(planenum & ~1); } -std::unique_ptr bspbrush_t::copy_unique() const +bspbrush_t::ptr bspbrush_t::copy_unique() const { - return std::make_unique(*this); + return bspbrush_t::make_ptr(*this); } /* @@ -347,7 +345,7 @@ std::optional LoadBrush(const mapentity_t *src, mapbrush_t *mapbrush //============================================================================= -static void Brush_LoadEntity(mapentity_t *dst, mapentity_t *src, const int hullnum, content_stats_base_t &stats, bspbrush_vector_t &brushes) +static void Brush_LoadEntity(mapentity_t *dst, mapentity_t *src, const int hullnum, content_stats_base_t &stats, bspbrush_t::container &brushes) { // _omitbrushes 1 just discards all brushes in the entity. // could be useful for geometry guides, selective compilation, etc. @@ -515,7 +513,7 @@ hullnum HULL_COLLISION should contain ALL brushes. (used by BSPX_CreateBrushList hullnum 0 does not contain clip brushes. ============ */ -void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_vector_t &brushes) +void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_t::container &brushes) { logging::funcheader(); diff --git a/qbsp/brushbsp.cc b/qbsp/brushbsp.cc index 1b8f86a5..a805859f 100644 --- a/qbsp/brushbsp.cc +++ b/qbsp/brushbsp.cc @@ -79,9 +79,9 @@ BrushFromBounds Creates a new axial brush ================== */ -std::unique_ptr BrushFromBounds(const aabb3d &bounds) +bspbrush_t::ptr BrushFromBounds(const aabb3d &bounds) { - auto b = std::make_unique(); + auto b = bspbrush_t::make_ptr(); b->sides.resize(6); for (int i = 0; i < 3; i++) { @@ -377,7 +377,7 @@ Creates a leaf node. Called in parallel. ================== */ -static void LeafNode(node_t *leafnode, std::vector> brushes, bspstats_t &stats) +static void LeafNode(node_t *leafnode, bspbrush_t::container brushes, bspstats_t &stats) { leafnode->facelist.clear(); leafnode->is_leaf = true; @@ -387,8 +387,8 @@ static void LeafNode(node_t *leafnode, std::vector> leafnode->contents = qbsp_options.target_game->combine_contents(leafnode->contents, brush->contents); } for (auto &brush : brushes) { - Q_assert(brush->original != nullptr); - leafnode->original_brushes.push_back(brush->original); + Q_assert(brush->mapbrush != nullptr); + leafnode->original_brushes.push_back(brush->mapbrush); } qbsp_options.target_game->count_contents_in_stats(leafnode->contents, *stats.leafstats); @@ -434,10 +434,10 @@ input. https://github.com/id-Software/Quake-2-Tools/blob/master/bsp/qbsp3/brushbsp.c#L935 ================ */ -static twosided> SplitBrush(std::unique_ptr brush, size_t planenum, bspstats_t &stats) +static twosided SplitBrush(bspbrush_t::ptr brush, size_t planenum, bspstats_t &stats) { const qplane3d &split = map.planes[planenum]; - twosided> result; + twosided result; // check all points vec_t d_front = 0; @@ -493,7 +493,7 @@ static twosided> SplitBrush(std::unique_ptr(); - result[i]->original = brush->original; + result[i]->mapbrush = brush->mapbrush; // fixme-brushbsp: add a bspbrush_t copy constructor to make sure we get all fields result[i]->contents = brush->contents; result[i]->sides.reserve(brush->sides.size() + 1); @@ -695,7 +695,7 @@ ChooseMidPlaneFromList The clipping hull BSP doesn't worry about avoiding splits ================== */ -static std::optional ChooseMidPlaneFromList(const std::vector> &brushes, const node_t *node, bspstats_t &stats) +static std::optional ChooseMidPlaneFromList(const bspbrush_t::container &brushes, const node_t *node, bspstats_t &stats) { vec_t bestaxialmetric = VECT_MAX; std::optional bestaxialplane; @@ -750,7 +750,7 @@ Using heuristics, chooses a plane to partition the brushes with. Returns nullopt if there are no valid planes to split with. ================ */ -static std::optional SelectSplitPlane(const std::vector> &brushes, node_t *node, std::optional forced_quick_tree, bspstats_t &stats) +static std::optional SelectSplitPlane(const bspbrush_t::container &brushes, node_t *node, std::optional forced_quick_tree, bspstats_t &stats) { // no brushes left to split, so we can't use any plane. if (!brushes.size()) { @@ -803,9 +803,9 @@ static std::optional SelectSplitPlane(const std::vectororiginal->contents.is_any_detail(qbsp_options.target_game)) + if ((pass & 1) && !brush->mapbrush->contents.is_any_detail(qbsp_options.target_game)) continue; - if (!(pass & 1) && brush->original->contents.is_any_detail(qbsp_options.target_game)) + if (!(pass & 1) && brush->mapbrush->contents.is_any_detail(qbsp_options.target_game)) continue; for (auto &side : brush->sides) { if (side.bevel) @@ -926,10 +926,10 @@ static std::optional SelectSplitPlane(const std::vector>, 2> SplitBrushList( - std::vector> brushes, size_t planenum, bspstats_t &stats) +static std::array SplitBrushList( + bspbrush_t::container brushes, size_t planenum, bspstats_t &stats) { - std::array>, 2> result; + std::array result; for (auto &brush : brushes) { int sides = brush->side; @@ -979,7 +979,7 @@ BuildTree_r Called in parallel. ================== */ -static void BuildTree_r(tree_t *tree, node_t *node, std::vector> brushes, std::optional forced_quick_tree, bspstats_t &stats) +static void BuildTree_r(tree_t *tree, node_t *node, bspbrush_t::container brushes, std::optional forced_quick_tree, bspstats_t &stats) { // find the best plane to use as a splitter auto bestplane = SelectSplitPlane(brushes, node, forced_quick_tree, stats); @@ -1021,10 +1021,10 @@ static void BuildTree_r(tree_t *tree, node_t *node, std::vectorvolume), bestplane.value(), stats); - node->volume = nullptr; - node->children[0]->volume = std::move(children_volumes[0]); - node->children[1]->volume = std::move(children_volumes[1]); + auto children_volumes = SplitBrush(std::move(node->volume), bestplane.value(), stats); + node->volume = nullptr; + node->children[0]->volume = std::move(children_volumes[0]); + node->children[1]->volume = std::move(children_volumes[1]); // recursively process children tbb::task_group g; @@ -1038,43 +1038,10 @@ static void BuildTree_r(tree_t *tree, node_t *node, std::vector BrushBSP_internal(mapentity_t *entity, std::vector> brushlist, std::optional forced_quick_tree) +std::unique_ptr BrushBSP(mapentity_t *entity, const bspbrush_t::container &brushlist, std::optional forced_quick_tree) { auto tree = std::make_unique(); - size_t c_faces = 0; - size_t c_nonvisfaces = 0; - size_t c_brushes = 0; - - for (const auto &b : brushlist) { - c_brushes++; - -#if 0 - // fixme-brushbsp: why does this just print and do nothing? should - // the brush be removed? - double volume = BrushVolume(*b); - if (volume < qbsp_options.microvolume.value()) { - logging::print("WARNING: {}: microbrush\n", - b->original->mapbrush->line); - } -#endif - - for (side_t &side : b->sides) { - if (side.bevel) - continue; - if (!side.w) - continue; - if (side.onnode) - continue; - if (side.source->visible) - c_faces++; - else - c_nonvisfaces++; - } - - tree->bounds += b->bounds; - } - if (brushlist.empty()) { /* * We allow an entity to be constructed with no visible brushes @@ -1102,20 +1069,52 @@ static std::unique_ptr BrushBSP_internal(mapentity_t *entity, std::vecto return tree; } + size_t c_faces = 0; + size_t c_nonvisfaces = 0; + size_t c_brushes = 0; + + for (const auto &b : brushlist) { + c_brushes++; + +#if 0 + // fixme-brushbsp: why does this just print and do nothing? should + // the brush be removed? + double volume = BrushVolume(*b); + if (volume < qbsp_options.microvolume.value()) { + logging::print("WARNING: {}: microbrush\n", + b->mapbrush->line); + } +#endif + + for (side_t &side : b->sides) { + if (side.bevel) + continue; + if (!side.w) + continue; + if (side.onnode) + continue; + if (side.source->visible) + c_faces++; + else + c_nonvisfaces++; + } + + tree->bounds += b->bounds; + } + logging::print(logging::flag::STAT, " {:8} brushes\n", c_brushes); logging::print(logging::flag::STAT, " {:8} visible faces\n", c_faces); logging::print(logging::flag::STAT, " {:8} nonvisible faces\n", c_nonvisfaces); auto node = tree->create_node(); - - node->volume = BrushFromBounds(tree->bounds.grow(SIDESPACE)); + node->volume = BrushFromBounds(tree->bounds.grow(SIDESPACE)); node->bounds = tree->bounds.grow(SIDESPACE); tree->headnode = node; bspstats_t stats{}; stats.leafstats = qbsp_options.target_game->create_content_stats(); - BuildTree_r(tree.get(), tree->headnode, std::move(brushlist), forced_quick_tree, stats); + BuildTree_r(tree.get(), tree->headnode, brushlist, forced_quick_tree, stats); logging::print(logging::flag::STAT, " {:8} visible nodes\n", stats.c_nodes - stats.c_nonvis); if (stats.c_nonvis) { @@ -1149,9 +1148,3 @@ static std::unique_ptr BrushBSP_internal(mapentity_t *entity, std::vecto return tree; } - -std::unique_ptr BrushBSP(mapentity_t *entity, const std::vector> &brushlist, std::optional forced_quick_tree) -{ - logging::funcheader(); - return BrushBSP_internal(entity, MakeBspBrushList(brushlist), forced_quick_tree); -} \ No newline at end of file diff --git a/qbsp/csg.cc b/qbsp/csg.cc index 93122056..ff71ca30 100644 --- a/qbsp/csg.cc +++ b/qbsp/csg.cc @@ -120,16 +120,3 @@ std::tuple, std::unique_ptr> SplitFace( return {std::move(new_front), std::move(new_back)}; } - -std::vector> MakeBspBrushList(const bspbrush_vector_t &brushes) -{ - // set the original pointers - std::vector> brushcopies; - for (const auto &original : brushes) { - auto copy = original->copy_unique(); - copy->original = original.get(); - brushcopies.push_back(std::move(copy)); - } - - return brushcopies; -} diff --git a/qbsp/faces.cc b/qbsp/faces.cc index 21bee8e9..af2fe533 100644 --- a/qbsp/faces.cc +++ b/qbsp/faces.cc @@ -472,7 +472,7 @@ see also FindPortalSide which populates p->side */ static std::unique_ptr FaceFromPortal(portal_t *p, bool pside) { - side_t *side = p->sides[pside]; + mapface_t *side = p->sides[pside]; if (!side) return nullptr; // portal does not bridge different visible contents @@ -481,7 +481,7 @@ static std::unique_ptr FaceFromPortal(portal_t *p, bool pside) f->texinfo = side->texinfo; f->planenum = (side->planenum & ~1) | (pside ? 1 : 0); f->portal = p; - f->original_side = side->source; + f->original_side = side; #if 0 bool make_face = diff --git a/qbsp/map.cc b/qbsp/map.cc index 4000bff3..bec70f15 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -1554,6 +1554,11 @@ const qbsp_plane_t &mapface_t::get_plane() const return map.get_plane(planenum); } +const qbsp_plane_t &mapface_t::get_positive_plane() const +{ + return map.get_plane(planenum & ~1); +} + bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec) { // TODO: This doesn't match how light does it (TexSpaceToWorld) @@ -2798,7 +2803,7 @@ WriteBspBrushMap from q3map ================== */ -void WriteBspBrushMap(const fs::path &name, const std::vector> &list) +void WriteBspBrushMap(const fs::path &name, const bspbrush_t::container &list) { std::shared_lock lock(map_planes_lock); @@ -2845,7 +2850,7 @@ from q3map */ static void TestExpandBrushes(mapentity_t *src) { - std::vector> hull1brushes; + bspbrush_t::container hull1brushes; for (auto &mapbrush : src->mapbrushes) { auto hull1brush = LoadBrush(src, &mapbrush, {CONTENTS_SOLID}, diff --git a/qbsp/outside.cc b/qbsp/outside.cc index d4cd4008..25fdc9d1 100644 --- a/qbsp/outside.cc +++ b/qbsp/outside.cc @@ -349,7 +349,7 @@ std::vector FindOccupiedClusters(node_t *headnode) //============================================================================= -static void MarkBrushSidesInvisible(mapentity_t *entity, bspbrush_vector_t &brushes) +static void MarkBrushSidesInvisible(mapentity_t *entity, bspbrush_t::container &brushes) { for (auto &brush : brushes) { for (auto &face : brush->sides) { @@ -412,13 +412,13 @@ static void MarkVisibleBrushSides_R(node_t *node) // optimized case: just mark the brush sides in the neighbouring // leaf that are coplanar for (auto *brush : neighbour_leaf->original_brushes) { - for (auto &side : brush->sides) { + for (auto &side : brush->faces) { // fixme-brushbsp: should this be get_plane() ? // fixme-brushbsp: planenum if (qv::epsilonEqual(side.get_positive_plane(), portal->plane)) { // we've found a brush side in an original brush in the neighbouring // leaf, on a portal to this (non-opaque) leaf, so mark it as visible. - side.source->visible = true; + side.visible = true; } } } @@ -600,7 +600,7 @@ get incorrectly marked as "invisible"). Special cases: structural fully covered by detail still needs to be marked "visible". =========== */ -bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes) +bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_t::container &brushes) { node_t *node = tree->headnode; @@ -720,7 +720,7 @@ bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_ return true; } -void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes) +void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_t::container &brushes) { logging::funcheader(); diff --git a/qbsp/portals.cc b/qbsp/portals.cc index 5696fe09..08e0a2e9 100644 --- a/qbsp/portals.cc +++ b/qbsp/portals.cc @@ -573,8 +573,8 @@ static mapentity_t *AreanodeEntityForLeaf(node_t *node) } for (auto &brush : node->original_brushes) { - if (brush->mapbrush->func_areaportal) { - return brush->mapbrush->func_areaportal; + if (brush->func_areaportal) { + return brush->func_areaportal; } } return nullptr; @@ -791,8 +791,8 @@ static void FindPortalSide(portal_t *p) return; // bestside[0] is the brushside visible on portal side[0] which is the positive side of the plane, always - side_t *bestside[2] = {nullptr, nullptr}; - side_t *exactside[2] = {nullptr, nullptr}; + mapface_t *bestside[2] = {nullptr, nullptr}; + mapface_t *exactside[2] = {nullptr, nullptr}; float bestdot = 0; const qbsp_plane_t &p1 = p->onnode->get_plane(); @@ -813,7 +813,7 @@ static void FindPortalSide(portal_t *p) continue; } - for (auto &side : brush->sides) { + for (auto &side : brush->faces) { if (side.bevel) continue; if ((side.planenum & ~1) == p->onnode->planenum) { @@ -899,7 +899,7 @@ static void MarkVisibleSides_r(node_t *node) FindPortalSide(p); for (int i = 0; i < 2; ++i) { if (p->sides[i]) { - p->sides[i]->source->visible = true; + p->sides[i]->visible = true; } } } @@ -911,7 +911,7 @@ MarkVisibleSides ============= */ -void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_vector_t &brushes) +void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_t::container &brushes) { logging::funcheader(); diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index f393a2df..dd1c2d5a 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -306,14 +306,13 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node) node->firstleafbrush = map.bsp.dleafbrushes.size(); for (auto &b : node->original_brushes) { - if (!b->mapbrush->outputnumber.has_value()) { - // FIXME - b->mapbrush->outputnumber = {static_cast(map.bsp.dbrushes.size())}; + if (!b->outputnumber.has_value()) { + b->outputnumber = {static_cast(map.bsp.dbrushes.size())}; dbrush_t &brush = map.bsp.dbrushes.emplace_back( dbrush_t{static_cast(map.bsp.dbrushsides.size()), 0, b->contents.native}); - for (auto &side : b->mapbrush->faces) { + for (auto &side : b->faces) { map.bsp.dbrushsides.push_back( {(uint32_t) ExportMapPlane(side.planenum), (int32_t)ExportMapTexinfo(side.texinfo)}); brush.numsides++; @@ -323,7 +322,7 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node) brush_state.total_brushes++; } - map.bsp.dleafbrushes.push_back(b->mapbrush->outputnumber.value()); + map.bsp.dleafbrushes.push_back(b->outputnumber.value()); } } } @@ -442,7 +441,7 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum) // reserve enough brushes; we would only make less, // never more - bspbrush_vector_t brushes; + bspbrush_t::container brushes; brushes.reserve(entity->mapbrushes.size()); /* diff --git a/qbsp/tree.cc b/qbsp/tree.cc index 7bec5456..e3bba442 100644 --- a/qbsp/tree.cc +++ b/qbsp/tree.cc @@ -82,9 +82,8 @@ static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents) node->original_brushes = std::move(node->children[base]->original_brushes); node->original_brushes.insert(node->original_brushes.end(), node->children[base ^ 1]->original_brushes.begin(), node->children[base ^ 1]->original_brushes.end()); - std::sort(node->original_brushes.begin(), node->original_brushes.end(), [](const bspbrush_t *a, const bspbrush_t *b) { - return a->mapbrush < b->mapbrush; - }); + // sort by pointer (since mapbrush_t is in a flat vector) + std::sort(node->original_brushes.begin(), node->original_brushes.end()); auto unique = std::unique(node->original_brushes.begin(), node->original_brushes.end()); node->original_brushes.erase(unique, node->original_brushes.end());