diff --git a/include/qbsp/map.hh b/include/qbsp/map.hh index 3e6c9ec4..28334560 100644 --- a/include/qbsp/map.hh +++ b/include/qbsp/map.hh @@ -108,6 +108,7 @@ public: mapentity_t *func_areaportal = nullptr; bool is_hint = false; // whether we are a hint brush or not (at least one side is "hint" or SURF_HINT) bool no_chop = false; // don't chop this + int32_t chop_index = 0; // chopping order; higher numbers chop lower numbers }; struct lumpdata diff --git a/qbsp/map.cc b/qbsp/map.cc index d70c8292..56d59677 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -3161,10 +3161,19 @@ void ProcessMapBrushes() brush.func_areaportal = areaportal; brush.is_hint = MapBrush_IsHint(brush); + // _chop signals that a brush does not partake in the BSP chopping phase. + // this allows brushes embedded in others to be retained. if (entity.epairs.has("_chop") && !entity.epairs.get_int("_chop")) { brush.no_chop = true; } + // brushes are sorted by their _chop_order; higher numbered brushes + // will "eat" lower numbered brushes. This effectively overrides the + // brush order of the map. + if (entity.epairs.has("_chop_order")) { + brush.chop_index = entity.epairs.get_int("_chop_order"); + } + // calculate brush bounds CalculateBrushBounds(brush); diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index cdeb666d..072265dc 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -1036,6 +1036,14 @@ static void ProcessEntity(mapentity_t &entity, hull_index_t hullnum) // always chop the other hulls to reduce brush tests if (qbsp_options.chop.value() || hullnum.value_or(0)) { + std::sort(brushes.begin(), brushes.end(), [](const bspbrush_t::ptr &a, const bspbrush_t::ptr &b) -> bool { + if (a->mapbrush->chop_index == b->mapbrush->chop_index) { + return a->mapbrush->line.line_number < b->mapbrush->line.line_number; + } + + return a->mapbrush->chop_index < b->mapbrush->chop_index; + }); + ChopBrushes(brushes, qbsp_options.chopfragment.value()); }