Merge branch 'brushbsp' of https://github.com/ericwa/ericw-tools into brushbsp

This commit is contained in:
Jonathan 2022-08-09 14:57:46 -04:00
commit b37917c9ca
20 changed files with 177 additions and 135 deletions

View File

@ -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 "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:bspinfo>")
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:bspinfo>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbbmalloc>" "$<TARGET_FILE_DIR:bspinfo>"
)
install(TARGETS bspinfo RUNTIME DESTINATION bin)

View File

@ -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 "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:bsputil>")
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:bsputil>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbbmalloc>" "$<TARGET_FILE_DIR:bsputil>"
)
install(TARGETS bsputil RUNTIME DESTINATION bin)

View File

@ -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)

View File

@ -14,6 +14,8 @@
#include <stdexcept>
#include <optional>
#include <tbb/scalable_allocator.h>
namespace polylib
{
@ -202,7 +204,7 @@ public:
struct winding_storage_heap_t
{
protected:
std::vector<qvec3d> values {};
std::vector<qvec3d, tbb::scalable_allocator<qvec3d>> values{};
public:
// default constructor does nothing

View File

@ -647,7 +647,7 @@ struct node_t
int firstface; // decision node only
int numfaces; // decision node only
twosided<std::unique_ptr<node_t>>
twosided<node_t *>
children; // children[0] = front side, children[1] = back side of plane. only valid for decision nodes
std::list<std::unique_ptr<face_t>> facelist; // decision nodes only, list for both sides

View File

@ -29,21 +29,32 @@
#include <memory>
#include <vector>
struct node_t;
#include <tbb/concurrent_vector.h>
struct portal_t;
struct tree_t
{
std::unique_ptr<node_t> 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<std::unique_ptr<portal_t>> 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<node_t> 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);

View File

@ -75,7 +75,9 @@ if (embree_FOUND)
add_custom_command(TARGET light POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:embree>" "$<TARGET_FILE_DIR:light>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:light>")
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:light>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbbmalloc>" "$<TARGET_FILE_DIR:light>"
)
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 $<TARGET_FILE:TBB::tbb> DESTINATION bin)
install(FILES $<TARGET_FILE:TBB::tbbmalloc> DESTINATION bin)
endif()
if (NOT EMBREE_LICENSE STREQUAL EMBREE_LICENSE-NOTFOUND)

View File

@ -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 "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:qbsp>")
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:qbsp>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbbmalloc>" "$<TARGET_FILE_DIR:qbsp>")

View File

@ -980,7 +980,7 @@ BuildTree_r
Called in parallel.
==================
*/
static void BuildTree_r(node_t *node, std::vector<std::unique_ptr<bspbrush_t>> brushes, std::optional<bool> forced_quick_tree, bspstats_t &stats)
static void BuildTree_r(tree_t *tree, node_t *node, std::vector<std::unique_ptr<bspbrush_t>> brushes, std::optional<bool> 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<std::unique_ptr<bspbrush_t>> b
// allocate children before recursing
for (int i = 0; i < 2; i++) {
auto &newnode = node->children[i] = std::make_unique<node_t>();
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<std::unique_ptr<bspbrush_t>> 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<tree_t> 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<node_t>();
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<node_t>();
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<node_t>();
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<tree_t> 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<node_t>();
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) {

View File

@ -133,8 +133,8 @@ static void ExportObj_Nodes_r(const node_t *node, std::vector<const face_t *> *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<const face_t *> *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;
}

View File

@ -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<int>(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_t> 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())

View File

@ -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<node_t *> &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);
}

View File

@ -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<std::unique_ptr<buildportal_t>> MakeHeadnodePortals(tree_t *tree)
p->winding = std::make_unique<winding_t>(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<winding_t> 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<buildportal_t> MakeNodePortal(node_t *node, const std::list<std:
new_portal->plane = node->get_plane();
new_portal->onnode = node;
new_portal->winding = std::make_unique<winding_t>(*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<std::list<std::unique_ptr<buildportal_t>>> SplitNodePortals(const node_t *node, std::list<std::unique_ptr<buildportal_t>> 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<std::list<std::unique_ptr<buildportal_t>>> 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<std::unique_ptr<buildportal_t>> 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<std::unique_ptr<buildportal_t>> merged_result;
merged_result.splice(merged_result.end(), front_fragments);
@ -482,8 +482,8 @@ std::list<std::unique_ptr<buildportal_t>> MakeTreePortals_r(tree_t *tree, node_t
std::list<std::unique_ptr<buildportal_t>> 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<std::unique_ptr<buildportal_t>> 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<std::unique_ptr<buildportal_t>> 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);
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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<face_t *> &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);
}
/*

View File

@ -36,6 +36,13 @@ portal_t *tree_t::create_portal()
return portals.emplace_back(std::make_unique<portal_t>()).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_t> &portal) {
@ -97,8 +104,8 @@ static void PruneNodes_R(node_t *node, std::atomic<int32_t> &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) &&

View File

@ -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<int32_t>(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<int32_t>(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.

View File

@ -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 "$<TARGET_FILE:embree>" "$<TARGET_FILE_DIR:tests>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:tests>")
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:tests>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbbmalloc>" "$<TARGET_FILE_DIR:tests>"
)
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}" "$<TARGET_FILE_DIR:tests>")

View File

@ -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 "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:vis>")
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbb>" "$<TARGET_FILE_DIR:vis>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:TBB::tbbmalloc>" "$<TARGET_FILE_DIR:vis>"
)
install(TARGETS vis RUNTIME DESTINATION bin)