/* Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 1997 Greg Lewis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See file, 'COPYING', for details. */ #include #include #include #include #include #include #include //============================================================================ portal_t *tree_t::create_portal() { return portals.emplace_back(std::make_unique()).get(); } /* ================== FreeTreePortals_r ================== */ static void ClearNodePortals_r(node_t *node) { if (!node->is_leaf) { ClearNodePortals_r(node->children[0].get()); ClearNodePortals_r(node->children[1].get()); } node->portals = nullptr; } void FreeTreePortals(tree_t *tree) { ClearNodePortals_r(tree->headnode.get()); tree->outside_node.portals = nullptr; tree->portals.clear(); } //============================================================================ static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents) { // merge the children's brush lists node->original_mapbrushes = node->children[0]->original_mapbrushes; node->original_mapbrushes.insert(node->children[1]->original_mapbrushes.begin(), node->children[1]->original_mapbrushes.end()); node->original_brushes.clear(); node->is_leaf = true; for (auto &child : node->children) { child = nullptr; } node->facelist.clear(); node->contents = contents; Q_assert(node->markfaces.empty()); } static void PruneNodes_R(node_t *node, std::atomic &count_pruned) { if (node->is_leaf) { node->original_brushes.clear(); return; } tbb::task_group g; g.run([&]() { PruneNodes_R(node->children[0].get(), count_pruned); }); g.run([&]() { PruneNodes_R(node->children[1].get(), count_pruned); }); g.wait(); if (node->children[0]->is_leaf && node->children[0]->contents.is_any_solid(qbsp_options.target_game) && node->children[1]->is_leaf && node->children[1]->contents.is_any_solid(qbsp_options.target_game)) { // This discards any faces on-node. Should be safe (?) ConvertNodeToLeaf(node, qbsp_options.target_game->create_solid_contents()); ++count_pruned; } else { node->original_brushes.clear(); } // DarkPlaces has an assertion that fails if both children are // solid. /* N.B.: CONTENTS_DETAIL_FENCE is not remapped to CONTENTS_SOLID until the very last moment, * because we want to generate a leaf (if we set it to CONTENTS_SOLID now it would use leaf 0). */ // fixme-brushbsp: corner case where two solid leafs shouldn't merge is two noclipfaces fence brushes touching // fixme-brushbsp: also merge other content types // fixme-brushbsp: maybe merge if same content type, and all faces on node are invisible? } void PruneNodes(node_t *node) { logging::funcheader(); std::atomic count_pruned = 0; PruneNodes_R(node, count_pruned); logging::print(logging::flag::STAT, " {:8} pruned nodes\n", count_pruned); }