From 7439fc30db06d0bd65e859c80d0e2dd792244fad Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 27 Jun 2022 22:40:38 -0600 Subject: [PATCH 1/6] testqbsp: fix absolute path in q1_wad_external --- qbsp/test_qbsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qbsp/test_qbsp.cc b/qbsp/test_qbsp.cc index d7012cd7..d24ec874 100644 --- a/qbsp/test_qbsp.cc +++ b/qbsp/test_qbsp.cc @@ -1608,7 +1608,7 @@ TEST_CASE("q1_wad_internal", "[testmaps_q1]") { * Test for WAD internal textures **/ TEST_CASE("q1_wad_external", "[testmaps_q1]") { - const auto [bsp, bspx, prt] = LoadTestmapQ1("qbsp_simple.map", { "-xwadpath", "A:\\ericw-tools\\testmaps" }); + const auto [bsp, bspx, prt] = LoadTestmapQ1("qbsp_simple.map", { "-xwadpath", std::string(testmaps_dir) }); CHECK(GAME_QUAKE == bsp.loadversion->game->id); From 29a622d106ec537e2ec5d23d4409df00fb12706d Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 27 Jun 2022 22:44:08 -0600 Subject: [PATCH 2/6] testqbsp: use -noverbose by default --- qbsp/test_qbsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qbsp/test_qbsp.cc b/qbsp/test_qbsp.cc index d24ec874..b42cbda2 100644 --- a/qbsp/test_qbsp.cc +++ b/qbsp/test_qbsp.cc @@ -169,7 +169,7 @@ static std::tuple> LoadTestmap(c auto bsp_path = map_path; bsp_path.replace_extension(".bsp"); - std::vector args{"", "-nopercent"}; // first arg is the exe path, which we're ignoring in this case + std::vector args{"", "-noverbose"}; // first arg is the exe path, which we're ignoring in this case for (auto &arg : extra_args) { args.push_back(arg); } From eb1f7acc02940dbcb745961aa42b8f80e86e0bbb Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Tue, 28 Jun 2022 00:06:18 -0600 Subject: [PATCH 3/6] qbsp: move PruneNodes to tree.cc for qbsp3 alignment --- include/qbsp/tree.hh | 27 ++++++++++ qbsp/CMakeLists.txt | 2 + qbsp/brushbsp.cc | 90 --------------------------------- qbsp/tree.cc | 115 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 90 deletions(-) create mode 100644 include/qbsp/tree.hh create mode 100644 qbsp/tree.cc diff --git a/include/qbsp/tree.hh b/include/qbsp/tree.hh new file mode 100644 index 00000000..ce4b9c4f --- /dev/null +++ b/include/qbsp/tree.hh @@ -0,0 +1,27 @@ +/* + 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. +*/ + +#pragma once + +struct node_t; + +void DetailToSolid(node_t *node); +void PruneNodes(node_t *node); diff --git a/qbsp/CMakeLists.txt b/qbsp/CMakeLists.txt index 2a747fc0..27d71c77 100644 --- a/qbsp/CMakeLists.txt +++ b/qbsp/CMakeLists.txt @@ -10,6 +10,7 @@ set(QBSP_INCLUDES ${CMAKE_SOURCE_DIR}/include/qbsp/prtfile.hh ${CMAKE_SOURCE_DIR}/include/qbsp/brushbsp.hh ${CMAKE_SOURCE_DIR}/include/qbsp/surfaces.hh + ${CMAKE_SOURCE_DIR}/include/qbsp/tree.hh ${CMAKE_SOURCE_DIR}/include/qbsp/writebsp.hh) set(QBSP_SOURCES @@ -24,6 +25,7 @@ set(QBSP_SOURCES ${CMAKE_SOURCE_DIR}/qbsp/brushbsp.cc ${CMAKE_SOURCE_DIR}/qbsp/surfaces.cc ${CMAKE_SOURCE_DIR}/qbsp/tjunc.cc + ${CMAKE_SOURCE_DIR}/qbsp/tree.cc ${CMAKE_SOURCE_DIR}/qbsp/writebsp.cc ${CMAKE_SOURCE_DIR}/qbsp/exportobj.cc ${QBSP_INCLUDES}) diff --git a/qbsp/brushbsp.cc b/qbsp/brushbsp.cc index f15c53c3..495b0746 100644 --- a/qbsp/brushbsp.cc +++ b/qbsp/brushbsp.cc @@ -45,96 +45,6 @@ static bool usemidsplit; */ static int mapbrushes; -//============================================================================ - -void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents) -{ - // merge the children's brush lists - node->original_brushes = concat( - node->children[0]->original_brushes, - node->children[1]->original_brushes); - sort_and_remove_duplicates(node->original_brushes); - - node->planenum = PLANENUM_LEAF; - - for (int i = 0; i < 2; ++i) { - delete node->children[i]; - node->children[i] = nullptr; - } - for (auto *face : node->facelist) { - delete face; - } - node->facelist = {}; - - node->contents = contents; - - Q_assert(node->markfaces.empty()); -} - -void DetailToSolid(node_t *node) -{ - if (node->planenum == PLANENUM_LEAF) { - if (options.target_game->id == GAME_QUAKE_II) { - return; - } - - // We need to remap CONTENTS_DETAIL to a standard quake content type - if (node->contents.is_detail_solid(options.target_game)) { - node->contents = options.target_game->create_solid_contents(); - } else if (node->contents.is_detail_illusionary(options.target_game)) { - node->contents = options.target_game->create_empty_contents(); - } - /* 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). - */ - return; - } else { - DetailToSolid(node->children[0]); - DetailToSolid(node->children[1]); - - // If both children are solid, we can merge the two leafs into one. - // DarkPlaces has an assertion that fails if both children are - // solid. - if (node->children[0]->contents.is_solid(options.target_game) && - node->children[1]->contents.is_solid(options.target_game)) { - // This discards any faces on-node. Should be safe (?) - ConvertNodeToLeaf(node, options.target_game->create_solid_contents()); - } - // fixme-brushbsp: merge with PruneNodes - } -} - -static void PruneNodes_R(node_t *node, int &count_pruned) -{ - if (node->planenum == PLANENUM_LEAF) { - return; - } - - PruneNodes_R(node->children[0], count_pruned); - PruneNodes_R(node->children[1], count_pruned); - - if (node->children[0]->planenum == PLANENUM_LEAF && node->children[0]->contents.is_solid(options.target_game) && - node->children[1]->planenum == PLANENUM_LEAF && node->children[1]->contents.is_solid(options.target_game)) { - // This discards any faces on-node. Should be safe (?) - ConvertNodeToLeaf(node, options.target_game->create_solid_contents()); - ++count_pruned; - } - - // 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::print(logging::flag::PROGRESS, "---- {} ----\n", __func__); - - int count_pruned = 0; - PruneNodes_R(node, count_pruned); - - logging::print(logging::flag::STAT, " {:8} pruned nodes\n", count_pruned); -} - /* ================== FaceSide diff --git a/qbsp/tree.cc b/qbsp/tree.cc new file mode 100644 index 00000000..bb33e93e --- /dev/null +++ b/qbsp/tree.cc @@ -0,0 +1,115 @@ +/* + 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 + +//============================================================================ + +static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents) +{ + // merge the children's brush lists + node->original_brushes = concat( + node->children[0]->original_brushes, + node->children[1]->original_brushes); + sort_and_remove_duplicates(node->original_brushes); + + node->planenum = PLANENUM_LEAF; + + for (int i = 0; i < 2; ++i) { + delete node->children[i]; + node->children[i] = nullptr; + } + for (auto *face : node->facelist) { + delete face; + } + node->facelist = {}; + + node->contents = contents; + + Q_assert(node->markfaces.empty()); +} + +void DetailToSolid(node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) { + if (options.target_game->id == GAME_QUAKE_II) { + return; + } + + // We need to remap CONTENTS_DETAIL to a standard quake content type + if (node->contents.is_detail_solid(options.target_game)) { + node->contents = options.target_game->create_solid_contents(); + } else if (node->contents.is_detail_illusionary(options.target_game)) { + node->contents = options.target_game->create_empty_contents(); + } + /* 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). + */ + return; + } else { + DetailToSolid(node->children[0]); + DetailToSolid(node->children[1]); + + // If both children are solid, we can merge the two leafs into one. + // DarkPlaces has an assertion that fails if both children are + // solid. + if (node->children[0]->contents.is_solid(options.target_game) && + node->children[1]->contents.is_solid(options.target_game)) { + // This discards any faces on-node. Should be safe (?) + ConvertNodeToLeaf(node, options.target_game->create_solid_contents()); + } + // fixme-brushbsp: merge with PruneNodes + } +} + +static void PruneNodes_R(node_t *node, int &count_pruned) +{ + if (node->planenum == PLANENUM_LEAF) { + return; + } + + PruneNodes_R(node->children[0], count_pruned); + PruneNodes_R(node->children[1], count_pruned); + + if (node->children[0]->planenum == PLANENUM_LEAF && node->children[0]->contents.is_solid(options.target_game) && + node->children[1]->planenum == PLANENUM_LEAF && node->children[1]->contents.is_solid(options.target_game)) { + // This discards any faces on-node. Should be safe (?) + ConvertNodeToLeaf(node, options.target_game->create_solid_contents()); + ++count_pruned; + } + + // 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::print(logging::flag::PROGRESS, "---- {} ----\n", __func__); + + int count_pruned = 0; + PruneNodes_R(node, count_pruned); + + logging::print(logging::flag::STAT, " {:8} pruned nodes\n", count_pruned); +} From c64b8692487b8df8b16216382b9c6ae7555fb025 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Tue, 28 Jun 2022 00:21:59 -0600 Subject: [PATCH 4/6] testqbsp: make winding test [.releaseonly] as it crashes on msvc debug builds --- qbsp/test_qbsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qbsp/test_qbsp.cc b/qbsp/test_qbsp.cc index b42cbda2..0577a599 100644 --- a/qbsp/test_qbsp.cc +++ b/qbsp/test_qbsp.cc @@ -1625,7 +1625,7 @@ TEST_CASE("q1_wad_external", "[testmaps_q1]") { CHECK(bsp.dtex.textures[3].data.size() == sizeof(dmiptex_t)); } -TEST_CASE("winding", "[benchmark]") { +TEST_CASE("winding", "[benchmark][.releaseonly]") { ankerl::nanobench::Bench bench; bench.run("std::vector reserve(3*4*6)", [&] { From b21e245d9920754d32bd58be75be0a52bb6ee265 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Tue, 28 Jun 2022 00:23:47 -0600 Subject: [PATCH 5/6] qbsp: surface.cc -> faces.cc --- include/qbsp/{surfaces.hh => faces.hh} | 0 qbsp/CMakeLists.txt | 4 ++-- qbsp/{surfaces.cc => faces.cc} | 0 qbsp/merge.cc | 2 +- qbsp/qbsp.cc | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename include/qbsp/{surfaces.hh => faces.hh} (100%) rename qbsp/{surfaces.cc => faces.cc} (100%) diff --git a/include/qbsp/surfaces.hh b/include/qbsp/faces.hh similarity index 100% rename from include/qbsp/surfaces.hh rename to include/qbsp/faces.hh diff --git a/qbsp/CMakeLists.txt b/qbsp/CMakeLists.txt index 27d71c77..80ef501d 100644 --- a/qbsp/CMakeLists.txt +++ b/qbsp/CMakeLists.txt @@ -9,7 +9,7 @@ set(QBSP_INCLUDES ${CMAKE_SOURCE_DIR}/include/qbsp/portals.hh ${CMAKE_SOURCE_DIR}/include/qbsp/prtfile.hh ${CMAKE_SOURCE_DIR}/include/qbsp/brushbsp.hh - ${CMAKE_SOURCE_DIR}/include/qbsp/surfaces.hh + ${CMAKE_SOURCE_DIR}/include/qbsp/faces.hh ${CMAKE_SOURCE_DIR}/include/qbsp/tree.hh ${CMAKE_SOURCE_DIR}/include/qbsp/writebsp.hh) @@ -23,7 +23,7 @@ set(QBSP_SOURCES ${CMAKE_SOURCE_DIR}/qbsp/prtfile.cc ${CMAKE_SOURCE_DIR}/qbsp/qbsp.cc ${CMAKE_SOURCE_DIR}/qbsp/brushbsp.cc - ${CMAKE_SOURCE_DIR}/qbsp/surfaces.cc + ${CMAKE_SOURCE_DIR}/qbsp/faces.cc ${CMAKE_SOURCE_DIR}/qbsp/tjunc.cc ${CMAKE_SOURCE_DIR}/qbsp/tree.cc ${CMAKE_SOURCE_DIR}/qbsp/writebsp.cc diff --git a/qbsp/surfaces.cc b/qbsp/faces.cc similarity index 100% rename from qbsp/surfaces.cc rename to qbsp/faces.cc diff --git a/qbsp/merge.cc b/qbsp/merge.cc index e76d7abc..82341b56 100644 --- a/qbsp/merge.cc +++ b/qbsp/merge.cc @@ -25,7 +25,7 @@ #include #include #include -#include +#include #ifdef PARANOID static void CheckColinear(face_t *f) diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index 7e1593d5..a944c7bc 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include From 1693bb3877fa5b07b7e9cac80a1bab9cc515ca25 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Tue, 28 Jun 2022 02:01:41 -0600 Subject: [PATCH 6/6] qbsp: side_t doesn't need sphere culling --- include/qbsp/brush.hh | 3 --- include/qbsp/csg4.hh | 1 - qbsp/brush.cc | 1 - qbsp/brushbsp.cc | 9 +-------- qbsp/csg4.cc | 10 ---------- 5 files changed, 1 insertion(+), 23 deletions(-) diff --git a/include/qbsp/brush.hh b/include/qbsp/brush.hh index 1cac2765..57e47c22 100644 --- a/include/qbsp/brush.hh +++ b/include/qbsp/brush.hh @@ -37,9 +37,6 @@ struct side_t int16_t lmshift; - qvec3d origin; - vec_t radius; - bool onnode; // has this face been used as a BSP node plane yet? bool visible = true; // can any part of this side be seen from non-void parts of the level? // non-visible means we can discard the brush side diff --git a/include/qbsp/csg4.hh b/include/qbsp/csg4.hh index d0a518a9..d3f15e5e 100644 --- a/include/qbsp/csg4.hh +++ b/include/qbsp/csg4.hh @@ -36,6 +36,5 @@ face_t *CopyFace(const face_t *in); face_t *MirrorFace(const face_t *face); std::tuple SplitFace(face_t *in, const qplane3d &split); void UpdateFaceSphere(face_t *in); -void UpdateFaceSphere(side_t *in); bool BrushGE(const bspbrush_t &a, const bspbrush_t &b); std::vector> ChopBrushes(const std::vector> &input); diff --git a/qbsp/brush.cc b/qbsp/brush.cc index db96de81..c931f331 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -459,7 +459,6 @@ static std::vector CreateBrushFaces(const mapentity_t *src, hullbrush_t f.planenum = FindPositivePlane(plane, &f.planeside); CheckFace(&f, mapface); - UpdateFaceSphere(&f); } // Rotatable objects must have a bounding box big enough to diff --git a/qbsp/brushbsp.cc b/qbsp/brushbsp.cc index 495b0746..3b069bec 100644 --- a/qbsp/brushbsp.cc +++ b/qbsp/brushbsp.cc @@ -111,14 +111,7 @@ inline int FaceSide(const face_t *in, const qbsp_plane_t &split) inline int FaceSide(const side_t *in, const qbsp_plane_t &split) { - vec_t dist = split.distance_to(in->origin); - - if (dist > in->radius) - return SIDE_FRONT; - else if (dist < -in->radius) - return SIDE_BACK; - else - return FaceSide__(in->w, split); + return FaceSide__(in->w, split); } /* diff --git a/qbsp/csg4.cc b/qbsp/csg4.cc index 4e6194ea..d7f21490 100644 --- a/qbsp/csg4.cc +++ b/qbsp/csg4.cc @@ -80,16 +80,6 @@ void UpdateFaceSphere(face_t *in) in->radius = sqrt(in->radius); } -void UpdateFaceSphere(side_t *in) -{ - in->origin = in->w.center(); - in->radius = 0; - for (size_t i = 0; i < in->w.size(); i++) { - in->radius = max(in->radius, qv::distance2(in->w[i], in->origin)); - } - in->radius = sqrt(in->radius); -} - /* ================== SplitFace