From ad65449cefefceb523d947ef9ed2633b879d0b21 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 11 Feb 2019 00:52:38 -0700 Subject: [PATCH] qbsp: add "-midsplitsurffraction n" option as an alt. to -maxnodesize switch to midsplit if the node contains more than this fraction of the model's total surfaces. Try 0.15 to 0.5. Works better than maxNodeSize for maps with a 3D skybox (e.g. +-128K unit maps) --- include/qbsp/qbsp.hh | 8 ++++++++ qbsp/qbsp.cc | 8 ++++++++ qbsp/solidbsp.cc | 33 +++++++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/qbsp/qbsp.hh b/include/qbsp/qbsp.hh index 4372b3db..7109b18b 100644 --- a/include/qbsp/qbsp.hh +++ b/include/qbsp/qbsp.hh @@ -358,6 +358,13 @@ public: int dxSubdivide; int dxLeakDist; int maxNodeSize; + /** + * if 0 (default), use maxNodeSize for deciding when to switch to midsplit bsp heuristic. + * + * if 0 < midsplitSurfFraction <=1, switch to midsplit if the node contains more than this fraction of the model's + * total surfaces. Try 0.15 to 0.5. Works better than maxNodeSize for maps with a 3D skybox (e.g. +-128K unit maps) + */ + float midsplitSurfFraction; char szMapName[512]; char szBSPName[512]; char wadPath[512]; @@ -390,6 +397,7 @@ public: this->fixRotateObjTexture = true; this->fOldaxis = true; this->maxNodeSize = 1024; + this->midsplitSurfFraction = 0; this->on_epsilon = 0.0001; this->worldExtent = 65536; } diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index c825dc79..07c46bf3 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -854,6 +854,14 @@ ParseOptions(char *szOptions) if (!szTok2) Error("Invalid argument to option %s", szTok); options.maxNodeSize= atoi(szTok2); + szTok = szTok2; + } else if (!Q_strcasecmp(szTok, "midsplitsurffraction")) { + szTok2 = GetTok(szTok + strlen(szTok) + 1, szEnd); + if (!szTok2) + Error("Invalid argument to option %s", szTok); + options.midsplitSurfFraction = qclamp(atof(szTok2), 0.0f, 1.0f); + logprint("Switching to midsplit when node contains more than fraction %f of model's surfaces\n", options.midsplitSurfFraction); + szTok = szTok2; } else if (!Q_strcasecmp(szTok, "epsilon")) { szTok2 = GetTok(szTok + strlen(szTok) + 1, szEnd); diff --git a/qbsp/solidbsp.cc b/qbsp/solidbsp.cc index 2f3f3ddc..269a6112 100644 --- a/qbsp/solidbsp.cc +++ b/qbsp/solidbsp.cc @@ -31,6 +31,11 @@ static int c_solid, c_empty, c_water, c_detail, c_detail_illusionary, c_detail_f static int c_illusionary_visblocker; static bool usemidsplit; +/** + * Total number of surfaces in the map + */ +static int mapsurfaces; + //============================================================================ void @@ -508,13 +513,24 @@ SelectPartition(surface_t *surfaces) maxs[i] = surf->maxs[i]; } - bool largenode = false; - if (options.maxNodeSize >= 64) { - const vec_t maxnodesize = options.maxNodeSize - ON_EPSILON; + // how much of the map are we partitioning? + double fractionOfMap = surfcount / (double)mapsurfaces; - largenode = (maxs[0] - mins[0]) > maxnodesize - || (maxs[1] - mins[1]) > maxnodesize - || (maxs[2] - mins[2]) > maxnodesize; + bool largenode = false; + + // decide if we should switch to the midsplit method + if (options.midsplitSurfFraction != 0.0) { + // new way (opt-in) + largenode = (fractionOfMap > options.midsplitSurfFraction); + } else { + // old way (ericw-tools 0.15.2+) + if (options.maxNodeSize >= 64) { + const vec_t maxnodesize = options.maxNodeSize - ON_EPSILON; + + largenode = (maxs[0] - mins[0]) > maxnodesize + || (maxs[1] - mins[1]) > maxnodesize + || (maxs[2] - mins[2]) > maxnodesize; + } } if (usemidsplit || largenode) // do fast way for clipping hull @@ -1044,6 +1060,11 @@ SolidBSP(const mapentity_t *entity, surface_t *surfhead, bool midsplit) c_detail_illusionary = 0; c_detail_fence = 0; c_illusionary_visblocker = 0; + // count map surfaces; this is used when deciding to switch between midsplit and the expensive partitioning + mapsurfaces = 0; + for (surface_t *surf = surfhead; surf; surf = surf->next) { + mapsurfaces++; + } PartitionSurfaces(surfhead, headnode);