diff --git a/bspinfo/CMakeLists.txt b/bspinfo/CMakeLists.txt index 025f6350..a8987d74 100644 --- a/bspinfo/CMakeLists.txt +++ b/bspinfo/CMakeLists.txt @@ -3,6 +3,8 @@ target_link_libraries(bspinfo common fmt::fmt) # HACK: copy .dll dependencies add_custom_command(TARGET bspinfo POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$") + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + ) install(TARGETS bspinfo RUNTIME DESTINATION bin) diff --git a/bsputil/CMakeLists.txt b/bsputil/CMakeLists.txt index e45d1301..8489c43b 100644 --- a/bsputil/CMakeLists.txt +++ b/bsputil/CMakeLists.txt @@ -4,10 +4,12 @@ set(BSPUTIL_SOURCES decompile.cpp) add_executable(bsputil ${BSPUTIL_SOURCES}) -target_link_libraries(bsputil common TBB::tbb fmt::fmt) +target_link_libraries(bsputil common TBB::tbb TBB::tbbmalloc fmt::fmt) # HACK: copy .dll dependencies add_custom_command(TARGET bsputil POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$") + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + ) install(TARGETS bsputil RUNTIME DESTINATION bin) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index f53ee8a4..ba15d8cf 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -35,4 +35,4 @@ add_library(common STATIC ${CMAKE_SOURCE_DIR}/include/common/prtfile.hh ${CMAKE_SOURCE_DIR}/include/common/vectorutils.hh) -target_link_libraries(common ${CMAKE_THREAD_LIBS_INIT} TBB::tbb fmt::fmt nlohmann_json::nlohmann_json) +target_link_libraries(common ${CMAKE_THREAD_LIBS_INIT} TBB::tbb TBB::tbbmalloc fmt::fmt nlohmann_json::nlohmann_json) diff --git a/include/common/polylib.hh b/include/common/polylib.hh index ba7f0bf1..f63f7820 100644 --- a/include/common/polylib.hh +++ b/include/common/polylib.hh @@ -14,6 +14,8 @@ #include #include +#include + namespace polylib { @@ -202,7 +204,7 @@ public: struct winding_storage_heap_t { protected: - std::vector values {}; + std::vector> values{}; public: // default constructor does nothing diff --git a/include/qbsp/qbsp.hh b/include/qbsp/qbsp.hh index 745755a1..69a0efc6 100644 --- a/include/qbsp/qbsp.hh +++ b/include/qbsp/qbsp.hh @@ -647,7 +647,7 @@ struct node_t int firstface; // decision node only int numfaces; // decision node only - twosided> + twosided children; // children[0] = front side, children[1] = back side of plane. only valid for decision nodes std::list> facelist; // decision nodes only, list for both sides diff --git a/include/qbsp/tree.hh b/include/qbsp/tree.hh index 50d58be3..724e4f39 100644 --- a/include/qbsp/tree.hh +++ b/include/qbsp/tree.hh @@ -29,21 +29,32 @@ #include #include -struct node_t; +#include + struct portal_t; struct tree_t { - std::unique_ptr headnode; + node_t *headnode; node_t outside_node = {}; // portals outside the world face this aabb3d bounds; // here for ownership/memory management - not intended to be iterated directly std::vector> portals; + // here for ownership/memory management - not intended to be iterated directly + // + // concurrent_vector allows BrushBSP to insert nodes in parallel, and also + // promises not to move elements so we can omit the std::unique_ptr wrapper. + tbb::concurrent_vector nodes; + // creates a new portal owned by `this` (stored in the `portals` vector) and // returns a raw pointer to it portal_t *create_portal(); + + // creates a new node owned by `this` (stored in the `nodes` vector) and + // returns a raw pointer to it + node_t *create_node(); }; void FreeTreePortals(tree_t *tree); diff --git a/light/CMakeLists.txt b/light/CMakeLists.txt index ed756b04..6615a83e 100644 --- a/light/CMakeLists.txt +++ b/light/CMakeLists.txt @@ -75,7 +75,9 @@ if (embree_FOUND) add_custom_command(TARGET light POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" - COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$") + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + ) if (NOT EMBREE_LICENSE STREQUAL EMBREE_LICENSE-NOTFOUND) add_custom_command(TARGET light POST_BUILD @@ -103,9 +105,18 @@ if (embree_FOUND) message(STATUS "TBB .so file: ${TBB_SO_FILE}") install(FILES ${TBB_SO_FILE} DESTINATION bin) + + # tbbmalloc + get_target_property(TBBMALLOC_SO_FILE_SYMLINK TBB::tbbmalloc IMPORTED_LOCATION_RELEASE) + get_filename_component(TBBMALLOC_SO_FILE "${TBBMALLOC_SO_FILE_SYMLINK}" REALPATH) + + message(STATUS "TBBMALLOC .so file: ${TBBMALLOC_SO_FILE}") + + install(FILES ${TBBMALLOC_SO_FILE} DESTINATION bin) else() # preferred method install(FILES $ DESTINATION bin) + install(FILES $ DESTINATION bin) endif() if (NOT EMBREE_LICENSE STREQUAL EMBREE_LICENSE-NOTFOUND) diff --git a/qbsp/CMakeLists.txt b/qbsp/CMakeLists.txt index 092b7095..21aebb4d 100644 --- a/qbsp/CMakeLists.txt +++ b/qbsp/CMakeLists.txt @@ -31,7 +31,7 @@ set(QBSP_SOURCES ${QBSP_INCLUDES}) add_library(libqbsp STATIC ${QBSP_SOURCES}) -target_link_libraries(libqbsp common ${CMAKE_THREAD_LIBS_INIT} TBB::tbb fmt::fmt nlohmann_json::nlohmann_json pareto) +target_link_libraries(libqbsp common ${CMAKE_THREAD_LIBS_INIT} TBB::tbb TBB::tbbmalloc fmt::fmt nlohmann_json::nlohmann_json pareto) add_executable(qbsp main.cc) target_link_libraries(qbsp libqbsp) @@ -40,4 +40,5 @@ install(TARGETS qbsp RUNTIME DESTINATION bin) # HACK: copy .dll dependencies add_custom_command(TARGET qbsp POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$") + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$") diff --git a/qbsp/brushbsp.cc b/qbsp/brushbsp.cc index 5bfd856f..a1449de0 100644 --- a/qbsp/brushbsp.cc +++ b/qbsp/brushbsp.cc @@ -980,7 +980,7 @@ BuildTree_r Called in parallel. ================== */ -static void BuildTree_r(node_t *node, std::vector> brushes, std::optional forced_quick_tree, bspstats_t &stats) +static void BuildTree_r(tree_t *tree, node_t *node, std::vector> 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); @@ -1008,7 +1008,7 @@ static void BuildTree_r(node_t *node, std::vector> b // allocate children before recursing for (int i = 0; i < 2; i++) { - auto &newnode = node->children[i] = std::make_unique(); + auto &newnode = node->children[i] = tree->create_node(); newnode->parent = node; newnode->bounds = node->bounds; } @@ -1021,14 +1021,16 @@ static void BuildTree_r(node_t *node, std::vector> b } } - auto children_volumes = SplitBrush(node->volume->copy_unique(), bestplane.value(), stats); + // to save time/memory we can destroy node's volume at this point + 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; - g.run([&]() { BuildTree_r(node->children[0].get(), std::move(children[0]), forced_quick_tree, stats); }); - g.run([&]() { BuildTree_r(node->children[1].get(), std::move(children[1]), forced_quick_tree, stats); }); + g.run([&]() { BuildTree_r(tree, node->children[0], std::move(children[0]), forced_quick_tree, stats); }); + g.run([&]() { BuildTree_r(tree, node->children[1], std::move(children[1]), forced_quick_tree, stats); }); g.wait(); } @@ -1079,22 +1081,22 @@ static std::unique_ptr BrushBSP_internal(mapentity_t *entity, std::vecto * collision hull for the engine. Probably could be done a little * smarter, but this works. */ - auto headnode = std::make_unique(); + auto headnode = tree->create_node(); headnode->bounds = entity->bounds; // The choice of plane is mostly unimportant, but having it at (0, 0, 0) affects // the node bounds calculation. headnode->planenum = 0; - headnode->children[0] = std::make_unique(); + headnode->children[0] = tree->create_node(); headnode->children[0]->is_leaf = true; headnode->children[0]->contents = qbsp_options.target_game->create_empty_contents(); - headnode->children[0]->parent = headnode.get(); - headnode->children[1] = std::make_unique(); + headnode->children[0]->parent = headnode; + headnode->children[1] = tree->create_node(); headnode->children[1]->is_leaf = true; headnode->children[1]->contents = qbsp_options.target_game->create_empty_contents(); - headnode->children[1]->parent = headnode.get(); + headnode->children[1]->parent = headnode; tree->bounds = headnode->bounds; - tree->headnode = std::move(headnode); + tree->headnode = headnode; return tree; } @@ -1103,16 +1105,16 @@ static std::unique_ptr BrushBSP_internal(mapentity_t *entity, std::vecto logging::print(logging::flag::STAT, " {:8} visible faces\n", c_faces); logging::print(logging::flag::STAT, " {:8} nonvisible faces\n", c_nonvisfaces); - auto node = std::make_unique(); + auto node = tree->create_node(); node->volume = BrushFromBounds(tree->bounds.grow(SIDESPACE)); node->bounds = tree->bounds.grow(SIDESPACE); - tree->headnode = std::move(node); + tree->headnode = node; bspstats_t stats{}; stats.leafstats = qbsp_options.target_game->create_content_stats(); - BuildTree_r(tree->headnode.get(), std::move(brushlist), forced_quick_tree, stats); + BuildTree_r(tree.get(), tree->headnode, std::move(brushlist), forced_quick_tree, stats); logging::print(logging::flag::STAT, " {:8} visible nodes\n", stats.c_nodes - stats.c_nonvis); if (stats.c_nonvis) { diff --git a/qbsp/exportobj.cc b/qbsp/exportobj.cc index ea501126..468f5019 100644 --- a/qbsp/exportobj.cc +++ b/qbsp/exportobj.cc @@ -133,8 +133,8 @@ static void ExportObj_Nodes_r(const node_t *node, std::vector *d dest->push_back(face.get()); } - ExportObj_Nodes_r(node->children[0].get(), dest); - ExportObj_Nodes_r(node->children[1].get(), dest); + ExportObj_Nodes_r(node->children[0], dest); + ExportObj_Nodes_r(node->children[1], dest); } void ExportObj_Nodes(const std::string &filesuffix, const node_t *nodes) @@ -147,8 +147,8 @@ void ExportObj_Nodes(const std::string &filesuffix, const node_t *nodes) static void ExportObj_Marksurfaces_r(const node_t *node, std::unordered_set *dest) { if (!node->is_leaf) { - ExportObj_Marksurfaces_r(node->children[0].get(), dest); - ExportObj_Marksurfaces_r(node->children[1].get(), dest); + ExportObj_Marksurfaces_r(node->children[0], dest); + ExportObj_Marksurfaces_r(node->children[1], dest); return; } diff --git a/qbsp/faces.cc b/qbsp/faces.cc index baaa7951..612b358b 100644 --- a/qbsp/faces.cc +++ b/qbsp/faces.cc @@ -101,8 +101,8 @@ static void EmitVertices_R(node_t *node) EmitFaceVertices(f.get()); } - EmitVertices_R(node->children[0].get()); - EmitVertices_R(node->children[1].get()); + EmitVertices_R(node->children[0]); + EmitVertices_R(node->children[1]); } void EmitVertices(node_t *headnode) @@ -184,8 +184,8 @@ static void MakeFaceEdges_r(node_t *node) FindFaceEdges(f.get()); } - MakeFaceEdges_r(node->children[0].get()); - MakeFaceEdges_r(node->children[1].get()); + MakeFaceEdges_r(node->children[0]); + MakeFaceEdges_r(node->children[1]); } /* @@ -253,8 +253,8 @@ static void EmitFaceFragments_R(node_t *node) node->numfaces = static_cast(map.bsp.dfaces.size()) - node->firstface; - EmitFaceFragments_R(node->children[0].get()); - EmitFaceFragments_R(node->children[1].get()); + EmitFaceFragments_R(node->children[0]); + EmitFaceFragments_R(node->children[1]); } /* @@ -299,10 +299,10 @@ static void AddMarksurfaces_r(face_t *face, std::unique_ptr face_copy, n auto [frontFragment, backFragment] = SplitFace(std::move(face_copy), splitplane); if (frontFragment) { - AddMarksurfaces_r(face, std::move(frontFragment), node->children[0].get()); + AddMarksurfaces_r(face, std::move(frontFragment), node->children[0]); } if (backFragment) { - AddMarksurfaces_r(face, std::move(backFragment), node->children[1].get()); + AddMarksurfaces_r(face, std::move(backFragment), node->children[1]); } } @@ -324,12 +324,12 @@ void MakeMarkFaces(node_t *node) // add this face to all descendant leafs it touches // make a copy we can clip - AddMarksurfaces_r(face.get(), CopyFace(face.get()), node->children[face->planenum & 1].get()); + AddMarksurfaces_r(face.get(), CopyFace(face.get()), node->children[face->planenum & 1]); } // process child nodes recursively - MakeMarkFaces(node->children[0].get()); - MakeMarkFaces(node->children[1].get()); + MakeMarkFaces(node->children[0]); + MakeMarkFaces(node->children[1]); } /* @@ -531,8 +531,8 @@ static void MakeFaces_r(node_t *node, makefaces_stats_t &stats) { // recurse down to leafs if (!node->is_leaf) { - MakeFaces_r(node->children[0].get(), stats); - MakeFaces_r(node->children[1].get(), stats); + MakeFaces_r(node->children[0], stats); + MakeFaces_r(node->children[1], stats); // merge together all visible faces on the node if (!qbsp_options.nomerge.value()) diff --git a/qbsp/outside.cc b/qbsp/outside.cc index 19b61ee5..626cd363 100644 --- a/qbsp/outside.cc +++ b/qbsp/outside.cc @@ -63,15 +63,15 @@ static node_t *PointInLeaf(node_t *node, const qvec3d &point) if (dist > 0) { // point is on the front of the node plane - return PointInLeaf(node->children[0].get(), point); + return PointInLeaf(node->children[0], point); } else if (dist < 0) { // point is on the back of the node plane - return PointInLeaf(node->children[1].get(), point); + return PointInLeaf(node->children[1], point); } else { // point is exactly on the node plane - node_t *front = PointInLeaf(node->children[0].get(), point); - node_t *back = PointInLeaf(node->children[1].get(), point); + node_t *front = PointInLeaf(node->children[0], point); + node_t *back = PointInLeaf(node->children[1], point); // prefer the opaque one if (LeafSealsMap(front)) { @@ -89,8 +89,8 @@ static void ClearOccupied_r(node_t *node) node->occupant = nullptr; if (!node->is_leaf) { - ClearOccupied_r(node->children[0].get()); - ClearOccupied_r(node->children[1].get()); + ClearOccupied_r(node->children[0]); + ClearOccupied_r(node->children[1]); } } @@ -117,8 +117,8 @@ static void MarkClusterOutsideDistance_R(node_t *node, int outside_distance) node->outside_distance = outside_distance; if (!node->is_leaf) { - MarkClusterOutsideDistance_R(node->children[0].get(), outside_distance); - MarkClusterOutsideDistance_R(node->children[1].get(), outside_distance); + MarkClusterOutsideDistance_R(node->children[0], outside_distance); + MarkClusterOutsideDistance_R(node->children[1], outside_distance); } } @@ -328,8 +328,8 @@ static void FindOccupiedClusters_R(node_t *node, std::vector &result) } if (!node->is_leaf) { - FindOccupiedClusters_R(node->children[0].get(), result); - FindOccupiedClusters_R(node->children[1].get(), result); + FindOccupiedClusters_R(node->children[0], result); + FindOccupiedClusters_R(node->children[1], result); } } @@ -363,8 +363,8 @@ static void MarkAllBrushSidesVisible_R(node_t *node) { // descend to leafs if (!node->is_leaf) { - MarkAllBrushSidesVisible_R(node->children[0].get()); - MarkAllBrushSidesVisible_R(node->children[1].get()); + MarkAllBrushSidesVisible_R(node->children[0]); + MarkAllBrushSidesVisible_R(node->children[1]); return; } @@ -387,8 +387,8 @@ static void MarkVisibleBrushSides_R(node_t *node) { // descent to leafs if (!node->is_leaf) { - MarkVisibleBrushSides_R(node->children[0].get()); - MarkVisibleBrushSides_R(node->children[1].get()); + MarkVisibleBrushSides_R(node->children[0]); + MarkVisibleBrushSides_R(node->children[1]); return; } @@ -432,8 +432,8 @@ static void MarkVisibleBrushSides_R(node_t *node) static void OutLeafsToSolid_r(node_t *node, int *outleafs_count, settings::filltype_t filltype) { if (!node->is_leaf) { - OutLeafsToSolid_r(node->children[0].get(), outleafs_count, filltype); - OutLeafsToSolid_r(node->children[1].get(), outleafs_count, filltype); + OutLeafsToSolid_r(node->children[0], outleafs_count, filltype); + OutLeafsToSolid_r(node->children[1], outleafs_count, filltype); return; } @@ -471,8 +471,8 @@ static int OutLeafsToSolid(node_t *node, settings::filltype_t filltype) static void SetOccupied_R(node_t *node, int dist) { if (!node->is_leaf) { - SetOccupied_R(node->children[0].get(), dist); - SetOccupied_R(node->children[1].get(), dist); + SetOccupied_R(node->children[0], dist); + SetOccupied_R(node->children[1], dist); } node->occupied = dist; @@ -601,7 +601,7 @@ Special cases: structural fully covered by detail still needs to be marked "visi */ bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes) { - node_t *node = tree->headnode.get(); + node_t *node = tree->headnode; logging::funcheader(); @@ -724,9 +724,9 @@ void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbr logging::funcheader(); // Clear the outside filling state on all nodes - ClearOccupied_r(tree->headnode.get()); + ClearOccupied_r(tree->headnode); MarkBrushSidesInvisible(entity, brushes); - MarkVisibleBrushSides_R(tree->headnode.get()); + MarkVisibleBrushSides_R(tree->headnode); } diff --git a/qbsp/portals.cc b/qbsp/portals.cc index 7b7fe8a3..2f88973d 100644 --- a/qbsp/portals.cc +++ b/qbsp/portals.cc @@ -43,7 +43,7 @@ contentflags_t ClusterContents(const node_t *node) return node->contents; return qbsp_options.target_game->cluster_contents( - ClusterContents(node->children[0].get()), ClusterContents(node->children[1].get())); + ClusterContents(node->children[0]), ClusterContents(node->children[1])); } /* @@ -160,9 +160,9 @@ std::list> MakeHeadnodePortals(tree_t *tree) p->winding = std::make_unique(BaseWindingForPlane(pl)); if (side) { - p->set_nodes(&tree->outside_node, tree->headnode.get()); + p->set_nodes(&tree->outside_node, tree->headnode); } else { - p->set_nodes(tree->headnode.get(), &tree->outside_node); + p->set_nodes(tree->headnode, &tree->outside_node); } } @@ -209,7 +209,7 @@ static std::optional BaseWindingForNode(const node_t *node) // clip by all the parents for (auto *np = node->parent; np && w;) { - if (np->children[0].get() == node) { + if (np->children[0] == node) { w = w->clip_front(np->get_plane(), BASE_WINDING_EPSILON, false); } else { w = w->clip_back(np->get_plane(), BASE_WINDING_EPSILON, false); @@ -267,7 +267,7 @@ std::unique_ptr MakeNodePortal(node_t *node, const std::listplane = node->get_plane(); new_portal->onnode = node; new_portal->winding = std::make_unique(*w); - new_portal->set_nodes(node->children[0].get(), node->children[1].get()); + new_portal->set_nodes(node->children[0], node->children[1]); return new_portal; } @@ -283,8 +283,8 @@ children have portals instead of node. twosided>> SplitNodePortals(const node_t *node, std::list> boundary_portals, portalstats_t &stats) { const auto &plane = node->get_plane(); - node_t *f = node->children[0].get(); - node_t *b = node->children[1].get(); + node_t *f = node->children[0]; + node_t *b = node->children[1]; twosided>> result; @@ -405,8 +405,8 @@ static void CalcTreeBounds_r(tree_t *tree, node_t *node) CalcNodeBounds(node); } else { tbb::task_group g; - g.run([&]() { CalcTreeBounds_r(tree, node->children[0].get()); }); - g.run([&]() { CalcTreeBounds_r(tree, node->children[1].get()); }); + g.run([&]() { CalcTreeBounds_r(tree, node->children[0]); }); + g.run([&]() { CalcTreeBounds_r(tree, node->children[1]); }); g.wait(); node->bounds = node->children[0]->bounds + node->children[1]->bounds; @@ -449,8 +449,8 @@ static std::list> ClipNodePortalsToTree_r(node_t auto boundary_portals_split = SplitNodePortals(node, std::move(portals), stats); - auto front_fragments = ClipNodePortalsToTree_r(node->children[0].get(), type, std::move(boundary_portals_split.front), stats); - auto back_fragments = ClipNodePortalsToTree_r(node->children[1].get(), type, std::move(boundary_portals_split.back), stats); + auto front_fragments = ClipNodePortalsToTree_r(node->children[0], type, std::move(boundary_portals_split.front), stats); + auto back_fragments = ClipNodePortalsToTree_r(node->children[1], type, std::move(boundary_portals_split.back), stats); std::list> merged_result; merged_result.splice(merged_result.end(), front_fragments); @@ -482,8 +482,8 @@ std::list> MakeTreePortals_r(tree_t *tree, node_t std::list> result_portals_front, result_portals_back; tbb::task_group g; - g.run([&]() { result_portals_front = MakeTreePortals_r(tree, node->children[0].get(), type, std::move(boundary_portals_split.front), stats); }); - g.run([&]() { result_portals_back = MakeTreePortals_r(tree, node->children[1].get(), type, std::move(boundary_portals_split.back), stats); }); + g.run([&]() { result_portals_front = MakeTreePortals_r(tree, node->children[0], type, std::move(boundary_portals_split.front), stats); }); + g.run([&]() { result_portals_back = MakeTreePortals_r(tree, node->children[1], type, std::move(boundary_portals_split.back), stats); }); g.wait(); // sequential part: push the nodeportal down each side of the bsp so it connects leafs @@ -495,9 +495,9 @@ std::list> MakeTreePortals_r(tree_t *tree, node_t // these portal fragments have node->children[1] on one side, and the leaf nodes from // node->children[0] on the other side std::list> half_clipped = - ClipNodePortalsToTree_r(node->children[0].get(), type, make_list(std::move(nodeportal)), stats); + ClipNodePortalsToTree_r(node->children[0], type, make_list(std::move(nodeportal)), stats); - for (auto &clipped_p : ClipNodePortalsToTree_r(node->children[1].get(), type, std::move(half_clipped), stats)) { + for (auto &clipped_p : ClipNodePortalsToTree_r(node->children[1], type, std::move(half_clipped), stats)) { result_portals_onnode.push_back(std::move(clipped_p)); } } @@ -527,13 +527,13 @@ void MakeTreePortals(tree_t *tree) auto headnodeportals = MakeHeadnodePortals(tree); - auto buildportals = MakeTreePortals_r(tree, tree->headnode.get(), portaltype_t::TREE, std::move(headnodeportals), stats); + auto buildportals = MakeTreePortals_r(tree, tree->headnode, portaltype_t::TREE, std::move(headnodeportals), stats); MakePortalsFromBuildportals(tree, std::move(buildportals)); logging::header("CalcTreeBounds"); - CalcTreeBounds_r(tree, tree->headnode.get()); + CalcTreeBounds_r(tree, tree->headnode); logging::print(logging::flag::STAT, " {:8} tiny portals\n", stats.c_tinyportals); logging::print(logging::flag::STAT, " {:8} tree portals\n", tree->portals.size()); @@ -544,14 +544,14 @@ static void AssertNoPortals_r(node_t *node) Q_assert(!node->portals); if (!node->is_leaf) { - AssertNoPortals_r(node->children[0].get()); - AssertNoPortals_r(node->children[1].get()); + AssertNoPortals_r(node->children[0]); + AssertNoPortals_r(node->children[1]); } } void AssertNoPortals(tree_t *tree) { - AssertNoPortals_r(tree->headnode.get()); + AssertNoPortals_r(tree->headnode); Q_assert(!tree->outside_node.portals); Q_assert(tree->portals.empty()); } @@ -569,8 +569,8 @@ static void ApplyArea_r(node_t *node) node->area = map.c_areas; if (!node->is_leaf) { - ApplyArea_r(node->children[0].get()); - ApplyArea_r(node->children[1].get()); + ApplyArea_r(node->children[0]); + ApplyArea_r(node->children[1]); } } @@ -578,10 +578,10 @@ static mapentity_t *AreanodeEntityForLeaf(node_t *node) { // if detail cluster, search the children recursively if (!node->is_leaf) { - if (auto *child0result = AreanodeEntityForLeaf(node->children[0].get()); child0result) { + if (auto *child0result = AreanodeEntityForLeaf(node->children[0]); child0result) { return child0result; } - return AreanodeEntityForLeaf(node->children[1].get()); + return AreanodeEntityForLeaf(node->children[1]); } for (auto &brush : node->original_brushes) { @@ -691,8 +691,8 @@ area set, flood fill out from there static void SetAreaPortalAreas_r(node_t *node) { if (!node->is_leaf) { - SetAreaPortalAreas_r(node->children[0].get()); - SetAreaPortalAreas_r(node->children[1].get()); + SetAreaPortalAreas_r(node->children[0]); + SetAreaPortalAreas_r(node->children[1]); return; } @@ -895,8 +895,8 @@ MarkVisibleSides_r static void MarkVisibleSides_r(node_t *node) { if (!node->is_leaf) { - MarkVisibleSides_r(node->children[0].get()); - MarkVisibleSides_r(node->children[1].get()); + MarkVisibleSides_r(node->children[0]); + MarkVisibleSides_r(node->children[1]); return; } @@ -938,5 +938,5 @@ void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_vector_t &brus } // set visible flags on the sides that are used by portals - MarkVisibleSides_r(tree->headnode.get()); + MarkVisibleSides_r(tree->headnode); } diff --git a/qbsp/prtfile.cc b/qbsp/prtfile.cc index 345bbf38..dffb4665 100644 --- a/qbsp/prtfile.cc +++ b/qbsp/prtfile.cc @@ -55,8 +55,8 @@ static void WritePortals_r(node_t *node, std::ofstream &portalFile, bool cluster qplane3d plane2; if (!node->is_leaf && !node->detail_separator) { - WritePortals_r(node->children[0].get(), portalFile, clusters); - WritePortals_r(node->children[1].get(), portalFile, clusters); + WritePortals_r(node->children[0], portalFile, clusters); + WritePortals_r(node->children[1], portalFile, clusters); return; } if (node->contents.is_solid(qbsp_options.target_game)) @@ -102,8 +102,8 @@ static void WritePortals_r(node_t *node, std::ofstream &portalFile, bool cluster static int WriteClusters_r(node_t *node, std::ofstream &portalFile, int viscluster) { if (!node->is_leaf) { - viscluster = WriteClusters_r(node->children[0].get(), portalFile, viscluster); - viscluster = WriteClusters_r(node->children[1].get(), portalFile, viscluster); + viscluster = WriteClusters_r(node->children[0], portalFile, viscluster); + viscluster = WriteClusters_r(node->children[1], portalFile, viscluster); return viscluster; } if (node->contents.is_solid(qbsp_options.target_game)) @@ -168,8 +168,8 @@ static void NumberLeafs_r(node_t *node, portal_state_t *state, int cluster) node->viscluster = cluster; CountPortals(node, state); } - NumberLeafs_r(node->children[0].get(), state, cluster); - NumberLeafs_r(node->children[1].get(), state, cluster); + NumberLeafs_r(node->children[0], state, cluster); + NumberLeafs_r(node->children[1], state, cluster); return; } @@ -270,12 +270,12 @@ void WritePortalFile(tree_t *tree) portalstats_t stats{}; // vis portal generation doesn't use headnode portals - auto buildportals = MakeTreePortals_r(tree, tree->headnode.get(), portaltype_t::VIS, {}, stats); + auto buildportals = MakeTreePortals_r(tree, tree->headnode, portaltype_t::VIS, {}, stats); MakePortalsFromBuildportals(tree, std::move(buildportals)); /* save portal file for vis tracing */ - WritePortalfile(tree->headnode.get(), &state); + WritePortalfile(tree->headnode, &state); logging::print(logging::flag::STAT, " {:8} vis leafs\n", state.num_visleafs); logging::print(logging::flag::STAT, " {:8} vis clusters\n", state.num_visclusters); diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index 4fbedf9b..5920e305 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -331,8 +331,8 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node) return; } - ExportBrushList_r(entity, node->children[0].get()); - ExportBrushList_r(entity, node->children[1].get()); + ExportBrushList_r(entity, node->children[0]); + ExportBrushList_r(entity, node->children[1]); } static void ExportBrushList(mapentity_t *entity, node_t *node) @@ -376,8 +376,8 @@ static void CountLeafs_r(node_t *node, content_stats_base_t &stats) qbsp_options.target_game->count_contents_in_stats(node->contents, stats); return; } - CountLeafs_r(node->children[0].get(), stats); - CountLeafs_r(node->children[1].get(), stats); + CountLeafs_r(node->children[0], stats); + CountLeafs_r(node->children[1], stats); } static void CountLeafs(node_t *headnode) @@ -486,10 +486,10 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum) // fill again so PruneNodes works MakeTreePortals(tree.get()); FillOutside(entity, tree.get(), hullnum, brushes); - PruneNodes(tree->headnode.get()); + PruneNodes(tree->headnode); } } - ExportClipNodes(entity, tree->headnode.get(), hullnum); + ExportClipNodes(entity, tree->headnode, hullnum); // fixme-brushbsp: return here? } else { @@ -521,8 +521,8 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum) // Area portals if (qbsp_options.target_game->id == GAME_QUAKE_II) { - FloodAreas(entity, tree->headnode.get()); - EmitAreaPortals(tree->headnode.get()); + FloodAreas(entity, tree->headnode); + EmitAreaPortals(tree->headnode); } } else { FillBrushEntity(entity, tree.get(), hullnum, brushes); @@ -534,39 +534,39 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum) MakeTreePortals(tree.get()); MarkVisibleSides(tree.get(), entity, brushes); - MakeFaces(tree->headnode.get()); + MakeFaces(tree->headnode); FreeTreePortals(tree.get()); - PruneNodes(tree->headnode.get()); + PruneNodes(tree->headnode); if (hullnum <= 0 && entity == map.world_entity() && (!map.leakfile || qbsp_options.keepprt.value())) { WritePortalFile(tree.get()); } // needs to come after any face creation - MakeMarkFaces(tree->headnode.get()); + MakeMarkFaces(tree->headnode); - CountLeafs(tree->headnode.get()); + CountLeafs(tree->headnode); // output vertices first, since TJunc needs it - EmitVertices(tree->headnode.get()); + EmitVertices(tree->headnode); - TJunc(tree->headnode.get()); + TJunc(tree->headnode); if (qbsp_options.objexport.value() && entity == map.world_entity()) { - ExportObj_Nodes("pre_makefaceedges_plane_faces", tree->headnode.get()); - ExportObj_Marksurfaces("pre_makefaceedges_marksurfaces", tree->headnode.get()); + ExportObj_Nodes("pre_makefaceedges_plane_faces", tree->headnode); + ExportObj_Marksurfaces("pre_makefaceedges_marksurfaces", tree->headnode); } Q_assert(entity->firstoutputfacenumber == -1); - entity->firstoutputfacenumber = MakeFaceEdges(tree->headnode.get()); + entity->firstoutputfacenumber = MakeFaceEdges(tree->headnode); if (qbsp_options.target_game->id == GAME_QUAKE_II) { - ExportBrushList(entity, tree->headnode.get()); + ExportBrushList(entity, tree->headnode); } - ExportDrawNodes(entity, tree->headnode.get(), entity->firstoutputfacenumber); + ExportDrawNodes(entity, tree->headnode, entity->firstoutputfacenumber); } } diff --git a/qbsp/tjunc.cc b/qbsp/tjunc.cc index def95ca1..c2f7ea2a 100644 --- a/qbsp/tjunc.cc +++ b/qbsp/tjunc.cc @@ -161,8 +161,8 @@ static void FindEdgeVerts_FaceBounds_R(const node_t *node, const aabb3d &aabb, s } } - FindEdgeVerts_FaceBounds_R(node->children[0].get(), aabb, verts); - FindEdgeVerts_FaceBounds_R(node->children[1].get(), aabb, verts); + FindEdgeVerts_FaceBounds_R(node->children[0], aabb, verts); + FindEdgeVerts_FaceBounds_R(node->children[1], aabb, verts); } /* @@ -845,8 +845,8 @@ static void FindFaces_r(node_t *node, std::unordered_set &faces) } } - FindFaces_r(node->children[0].get(), faces); - FindFaces_r(node->children[1].get(), faces); + FindFaces_r(node->children[0], faces); + FindFaces_r(node->children[1], faces); } /* diff --git a/qbsp/tree.cc b/qbsp/tree.cc index 0c3463f3..08690cf5 100644 --- a/qbsp/tree.cc +++ b/qbsp/tree.cc @@ -36,6 +36,13 @@ portal_t *tree_t::create_portal() return portals.emplace_back(std::make_unique()).get(); } +node_t *tree_t::create_node() +{ + auto it = nodes.grow_by(1); + + return &(*it); +} + /* ================== FreeTreePortals_r @@ -45,8 +52,8 @@ 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()); + ClearNodePortals_r(node->children[0]); + ClearNodePortals_r(node->children[1]); } node->portals = nullptr; @@ -56,7 +63,7 @@ static void ClearNodePortals_r(node_t *node) void FreeTreePortals(tree_t *tree) { - ClearNodePortals_r(tree->headnode.get()); + ClearNodePortals_r(tree->headnode); tree->outside_node.portals = nullptr; tbb::parallel_for_each(tree->portals, [](std::unique_ptr &portal) { @@ -97,8 +104,8 @@ static void PruneNodes_R(node_t *node, std::atomic &count_pruned) } 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.run([&]() { PruneNodes_R(node->children[0], count_pruned); }); + g.run([&]() { PruneNodes_R(node->children[1], count_pruned); }); g.wait(); if (node->children[0]->is_leaf && node->children[0]->contents.is_any_solid(qbsp_options.target_game) && diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index ef426caf..31a100bc 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -103,8 +103,8 @@ static size_t ExportClipNodes(node_t *node) const size_t nodenum = map.bsp.dclipnodes.size(); map.bsp.dclipnodes.emplace_back(); - const int child0 = ExportClipNodes(node->children[0].get()); - const int child1 = ExportClipNodes(node->children[1].get()); + const int child0 = ExportClipNodes(node->children[0]); + const int child1 = ExportClipNodes(node->children[1]); // Careful not to modify the vector while using this clipnode pointer bsp2_dclipnode_t &clipnode = map.bsp.dclipnodes[nodenum]; @@ -219,12 +219,12 @@ static void ExportDrawNodes(node_t *node) int32_t nextLeafIndex = static_cast(map.bsp.dleafs.size()); const int32_t childnum = -(nextLeafIndex + 1); dnode->children[i] = childnum; - ExportLeaf(node->children[i].get()); + ExportLeaf(node->children[i]); } } else { const int32_t childnum = static_cast(map.bsp.dnodes.size()); dnode->children[i] = childnum; - ExportDrawNodes(node->children[i].get()); + ExportDrawNodes(node->children[i]); // Important: our dnode pointer may be invalid after the recursive call, if the vector got resized. // So re-set the pointer. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 83c864ba..b0761edb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,12 +23,14 @@ if (NOT EMBREE_TBB_DLL STREQUAL EMBREE_TBB_DLL-NOTFOUND) message(STATUS "Found embree EMBREE_TBB_DLL: ${EMBREE_TBB_DLL}") endif() -target_link_libraries(tests libqbsp liblight libvis common TBB::tbb Catch2::Catch2WithMain fmt::fmt nanobench::nanobench) +target_link_libraries(tests libqbsp liblight libvis common TBB::tbb TBB::tbbmalloc Catch2::Catch2WithMain fmt::fmt nanobench::nanobench) # HACK: copy .dll dependencies add_custom_command(TARGET tests POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" - COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$") + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + ) if (NOT EMBREE_TBB_DLL STREQUAL EMBREE_TBB_DLL-NOTFOUND) add_custom_command(TARGET tests POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${EMBREE_TBB_DLL}" "$") diff --git a/vis/CMakeLists.txt b/vis/CMakeLists.txt index 1177b87a..20525f5a 100644 --- a/vis/CMakeLists.txt +++ b/vis/CMakeLists.txt @@ -23,6 +23,8 @@ target_link_libraries(vis PRIVATE common libvis) # HACK: copy .dll dependencies add_custom_command(TARGET vis POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$") + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$" + ) install(TARGETS vis RUNTIME DESTINATION bin)