this all matches release now

This commit is contained in:
Jonathan 2022-08-02 04:29:36 -04:00
parent cc9dd986c6
commit 8476e2861c
4 changed files with 76 additions and 40 deletions

View File

@ -41,4 +41,4 @@ bool WindingIsTiny(const winding_t &w, double size = EDGE_LENGTH_EPSILON);
std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds); std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds);
// compatibility version // compatibility version
std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, bool use_mid_split); std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::optional<bool> forced_quick_tree);

View File

@ -352,7 +352,7 @@ public:
// since the max world size in Q3 is {-65536, -65536, -65536, 65536, 65536, 65536}. should we dynamically change this? // since the max world size in Q3 is {-65536, -65536, -65536, 65536, 65536, 65536}. should we dynamically change this?
// should we automatically turn this on if the world gets too big but leave it off for smaller worlds? // should we automatically turn this on if the world gets too big but leave it off for smaller worlds?
setting_blocksize blocksize{this, "blocksize", { 0, 0, 0 }, &common_format_group, "from q3map2; split the world by x/y/z sized chunks, speeding up split decisions"}; setting_blocksize blocksize{this, "blocksize", { 0, 0, 0 }, &common_format_group, "from q3map2; split the world by x/y/z sized chunks, speeding up split decisions"};
setting_int32 midsplitbrushes{this, "midsplitbrushes", 128, &common_format_group, "switch to cheaper partitioning if a node contains this many brushes"}; setting_numeric<vec_t> midsplitbrushfraction{this, "midsplitbrushfraction", 0.0, &common_format_group, "switch to cheaper partitioning if a node contains this % of brushes in the map"};
void setParameters(int argc, const char **argv) override void setParameters(int argc, const char **argv) override
{ {

View File

@ -626,7 +626,7 @@ static void CheckPlaneAgainstParents(const qbsp_plane_t &plane, node_t *node)
} }
} }
static bool CheckPlaneAgainstVolume(const qbsp_plane_t &plane, node_t *node) static bool CheckPlaneAgainstVolume(const qbsp_plane_t &plane, const node_t *node)
{ {
auto [front, back] = SplitBrush(node->volume->copy_unique(), plane); auto [front, back] = SplitBrush(node->volume->copy_unique(), plane);
@ -712,7 +712,7 @@ ChooseMidPlaneFromList
The clipping hull BSP doesn't worry about avoiding splits The clipping hull BSP doesn't worry about avoiding splits
================== ==================
*/ */
static std::optional<qbsp_plane_t> ChooseMidPlaneFromList(const std::vector<std::unique_ptr<bspbrush_t>> &brushes, const aabb3d &bounds) static std::optional<qbsp_plane_t> ChooseMidPlaneFromList(const std::vector<std::unique_ptr<bspbrush_t>> &brushes, const node_t *node)
{ {
vec_t bestaxialmetric = VECT_MAX; vec_t bestaxialmetric = VECT_MAX;
std::optional<qbsp_plane_t> bestaxialplane; std::optional<qbsp_plane_t> bestaxialplane;
@ -730,8 +730,13 @@ static std::optional<qbsp_plane_t> ChooseMidPlaneFromList(const std::vector<std:
} }
const qbsp_plane_t &plane = side.plane; const qbsp_plane_t &plane = side.plane;
if (!CheckPlaneAgainstVolume(plane, node)) {
continue; // would produce a tiny volume
}
/* calculate the split metric, smaller values are better */ /* calculate the split metric, smaller values are better */
const vec_t metric = SplitPlaneMetric(plane, bounds); const vec_t metric = SplitPlaneMetric(plane, node->bounds);
if (metric < bestanymetric) { if (metric < bestanymetric) {
bestanymetric = metric; bestanymetric = metric;
@ -761,46 +766,77 @@ Using heuristics, chooses a plane to partition the brushes with.
Returns nullopt if there are no valid planes to split with. Returns nullopt if there are no valid planes to split with.
================ ================
*/ */
static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::unique_ptr<bspbrush_t>> &brushes, node_t *node, bool use_mid_split, bspstats_t &stats) static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::unique_ptr<bspbrush_t>> &brushes, node_t *node, std::optional<bool> forced_quick_tree, bspstats_t &stats)
{ {
// no brushes left to split, so we can't use any plane. // no brushes left to split, so we can't use any plane.
if (!brushes.size()) { if (!brushes.size()) {
return std::nullopt; return std::nullopt;
} }
// if it is crossing a block boundary, force a split; // if forced_quick_tree is nullopt, we will choose fast/slow based on
// this is optional q3map2 mode // certain parameters.
for (size_t i = 0; i < 3; i++) { if (!forced_quick_tree.has_value() || forced_quick_tree.value() == true) {
if (qbsp_options.blocksize.value()[i] <= 0) { // if it is crossing a block boundary, force a split;
continue; // this is optional q3map2 mode that is disabled by default.
} if (qbsp_options.blocksize.isChanged()) {
for (size_t i = 0; i < 3; i++) {
if (qbsp_options.blocksize.value()[i] <= 0) {
continue;
}
vec_t dist = qbsp_options.blocksize.value()[i] * (floor(node->bounds.mins()[i] / qbsp_options.blocksize.value()[i]) + 1); vec_t dist = qbsp_options.blocksize.value()[i] * (floor(node->bounds.mins()[i] / qbsp_options.blocksize.value()[i]) + 1);
if (node->bounds.maxs()[i] > dist) { if (node->bounds.maxs()[i] > dist) {
qplane3d plane{}; qplane3d plane{};
plane.normal[i] = 1.0; plane.normal[i] = 1.0;
plane.dist = dist; plane.dist = dist;
qbsp_plane_t bsp_plane = plane; qbsp_plane_t bsp_plane = plane;
stats.c_blocksplit++;
for (auto &b : brushes) { if (!CheckPlaneAgainstVolume(bsp_plane, node)) {
b->side = TestBrushToPlanenum(*b, bsp_plane, nullptr, nullptr, nullptr); continue; // would produce a tiny volume
}
stats.c_blocksplit++;
for (auto &b : brushes) {
b->side = TestBrushToPlanenum(*b, bsp_plane, nullptr, nullptr, nullptr);
}
return bsp_plane;
}
}
}
if (!forced_quick_tree.has_value()) {
// decide if we should switch to the midsplit method
if (qbsp_options.midsplitbrushfraction.value() != 0.0) {
// new way (opt-in)
// how much of the map are we partitioning?
double fractionOfMap = brushes.size() / (double) map.brushes.size();
forced_quick_tree = (fractionOfMap > qbsp_options.midsplitbrushfraction.value());
} else {
// old way (ericw-tools 0.15.2+)
if (qbsp_options.maxnodesize.value() >= 64) {
const vec_t maxnodesize = qbsp_options.maxnodesize.value() - qbsp_options.epsilon.value();
forced_quick_tree = (node->bounds.maxs()[0] - node->bounds.mins()[0]) > maxnodesize
|| (node->bounds.maxs()[1] - node->bounds.mins()[1]) > maxnodesize
|| (node->bounds.maxs()[2] - node->bounds.mins()[2]) > maxnodesize;
}
} }
}
return bsp_plane; if (forced_quick_tree.value()) {
} if (auto mid_plane = ChooseMidPlaneFromList(brushes, node)) {
} stats.c_midsplit++;
if (brushes.size() >= qbsp_options.midsplitbrushes.value() || use_mid_split) { for (auto &b : brushes) {
if (auto mid_plane = ChooseMidPlaneFromList(brushes, node->bounds)) { b->side = TestBrushToPlanenum(*b, mid_plane.value(), nullptr, nullptr, nullptr);
stats.c_midsplit++; }
for (auto &b : brushes) { return mid_plane;
b->side = TestBrushToPlanenum(*b, mid_plane.value(), nullptr, nullptr, nullptr);
} }
return mid_plane;
} }
} }
@ -991,10 +1027,10 @@ BuildTree_r
Called in parallel. Called in parallel.
================== ==================
*/ */
static void BuildTree_r(node_t *node, std::vector<std::unique_ptr<bspbrush_t>> brushes, bool use_mid_split, bspstats_t &stats) static void BuildTree_r(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 // find the best plane to use as a splitter
auto bestplane = SelectSplitPlane(brushes, node, use_mid_split, stats); auto bestplane = SelectSplitPlane(brushes, node, forced_quick_tree, stats);
if (!bestplane) { if (!bestplane) {
// this is a leaf node // this is a leaf node
@ -1034,8 +1070,8 @@ static void BuildTree_r(node_t *node, std::vector<std::unique_ptr<bspbrush_t>> b
// recursively process children // recursively process children
tbb::task_group g; tbb::task_group g;
g.run([&]() { BuildTree_r(node->children[0].get(), std::move(children[0]), use_mid_split, stats); }); 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]), use_mid_split, stats); }); g.run([&]() { BuildTree_r(node->children[1].get(), std::move(children[1]), forced_quick_tree, stats); });
g.wait(); g.wait();
} }
@ -1044,7 +1080,7 @@ static void BuildTree_r(node_t *node, std::vector<std::unique_ptr<bspbrush_t>> b
BrushBSP BrushBSP
================== ==================
*/ */
static std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::vector<std::unique_ptr<bspbrush_t>> brushlist, bool use_mid_split) static std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::vector<std::unique_ptr<bspbrush_t>> brushlist, std::optional<bool> forced_quick_tree)
{ {
auto tree = std::make_unique<tree_t>(); auto tree = std::make_unique<tree_t>();
@ -1120,7 +1156,7 @@ static std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::vector<std::un
bspstats_t stats{}; bspstats_t stats{};
stats.leafstats = qbsp_options.target_game->create_content_stats(); stats.leafstats = qbsp_options.target_game->create_content_stats();
BuildTree_r(tree->headnode.get(), std::move(brushlist), use_mid_split, stats); BuildTree_r(tree->headnode.get(), std::move(brushlist), forced_quick_tree, stats);
logging::print(logging::flag::STAT, " {:8} visible nodes\n", stats.c_nodes - stats.c_nonvis); logging::print(logging::flag::STAT, " {:8} visible nodes\n", stats.c_nodes - stats.c_nonvis);
logging::print(logging::flag::STAT, " {:8} nonvis nodes\n", stats.c_nonvis); logging::print(logging::flag::STAT, " {:8} nonvis nodes\n", stats.c_nonvis);
@ -1133,7 +1169,7 @@ static std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::vector<std::un
return tree; return tree;
} }
std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, bool use_mid_split) std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::optional<bool> forced_quick_tree)
{ {
return BrushBSP(entity, MakeBspBrushList(entity), use_mid_split); return BrushBSP(entity, MakeBspBrushList(entity), forced_quick_tree);
} }

View File

@ -609,7 +609,7 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
if (qbsp_options.forcegoodtree.value()) { if (qbsp_options.forcegoodtree.value()) {
tree = BrushBSP(entity, false); tree = BrushBSP(entity, false);
} else { } else {
tree = BrushBSP(entity, entity == map.world_entity()); tree = BrushBSP(entity, entity == map.world_entity() ? std::nullopt : std::optional<bool>(false));
} }
// build all the portals in the bsp tree // build all the portals in the bsp tree