side_t using planenums

This commit is contained in:
Jonathan 2022-08-02 14:55:38 -04:00
parent 1ad0eb530d
commit 1d729ba573
9 changed files with 75 additions and 60 deletions

View File

@ -33,8 +33,7 @@ struct maptexinfo_t;
struct side_t struct side_t
{ {
winding_t w; winding_t w;
qbsp_plane_t plane; size_t planenum;
bool plane_flipped; // whether `plane` is flipped or not
int texinfo; int texinfo;
int16_t lmshift; int16_t lmshift;
@ -48,6 +47,8 @@ struct side_t
bool tested; bool tested;
const maptexinfo_t &get_texinfo() const; const maptexinfo_t &get_texinfo() const;
const qbsp_plane_t &get_plane() const;
const qbsp_plane_t &get_positive_plane() const;
}; };
class mapbrush_t; class mapbrush_t;

View File

@ -164,6 +164,19 @@ struct mapdata_t
return planes.size() - 2; return planes.size() - 2;
} }
// find the specified plane in the list if it exists. throws
// if not.
inline size_t find_plane(const qplane3d &plane)
{
for (size_t i = 0; i < planes.size(); i++) {
if (qv::epsilonEqual(planes[i], plane)) {
return i;
}
}
throw std::bad_function_call();
}
// find the specified plane in the list if it exists, or // find the specified plane in the list if it exists, or
// return a new one // return a new one
inline size_t add_or_find_plane(const qplane3d &plane) inline size_t add_or_find_plane(const qplane3d &plane)

View File

@ -38,6 +38,16 @@ const maptexinfo_t &side_t::get_texinfo() const
return map.mtexinfos[this->texinfo]; return map.mtexinfos[this->texinfo];
} }
const qbsp_plane_t &side_t::get_plane() const
{
return map.get_plane(planenum);
}
const qbsp_plane_t &side_t::get_positive_plane() const
{
return map.get_plane(planenum & ~1);
}
std::unique_ptr<bspbrush_t> bspbrush_t::copy_unique() const std::unique_ptr<bspbrush_t> bspbrush_t::copy_unique() const
{ {
return std::make_unique<bspbrush_t>(*this); return std::make_unique<bspbrush_t>(*this);
@ -80,11 +90,7 @@ qplane3d Face_Plane(const face_t *face)
qplane3d Face_Plane(const side_t *face) qplane3d Face_Plane(const side_t *face)
{ {
if (face->plane_flipped) { return face->get_plane();
return -face->plane;
}
return face->plane;
} }
/* /*
@ -96,8 +102,6 @@ Note: this will not catch 0 area polygons
*/ */
static void CheckFace(side_t *face, const mapface_t &sourceface) static void CheckFace(side_t *face, const mapface_t &sourceface)
{ {
const qplane3d &plane = face->plane;
if (face->w.size() < 3) { if (face->w.size() < 3) {
if (face->w.size() == 2) { if (face->w.size() == 2) {
logging::print( logging::print(
@ -112,11 +116,8 @@ static void CheckFace(side_t *face, const mapface_t &sourceface)
return; return;
} }
qvec3d facenormal = plane.normal; const qbsp_plane_t &plane = face->get_plane();
qvec3d facenormal = plane.get_normal();
if (face->plane_flipped) {
facenormal = -facenormal;
}
for (size_t i = 0; i < face->w.size(); i++) { for (size_t i = 0; i < face->w.size(); i++) {
const qvec3d &p1 = face->w[i]; const qvec3d &p1 = face->w[i];
@ -326,7 +327,7 @@ static std::vector<side_t> CreateBrushFaces(const mapentity_t *src, hullbrush_t
plane.dist = qv::dot(plane.normal, point); plane.dist = qv::dot(plane.normal, point);
f.texinfo = hullnum > 0 ? 0 : mapface.texinfo; f.texinfo = hullnum > 0 ? 0 : mapface.texinfo;
f.plane_flipped = f.plane.set_plane(plane, true); f.planenum = map.add_or_find_plane(plane);
CheckFace(&f, mapface); CheckFace(&f, mapface);
} }

View File

@ -116,7 +116,7 @@ std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds)
plane.dist = bounds.maxs()[i]; plane.dist = bounds.maxs()[i];
side_t &side = b->sides[i]; side_t &side = b->sides[i];
side.plane_flipped = side.plane.set_plane(plane, true); side.planenum = map.add_or_find_plane(plane);
} }
{ {
@ -125,7 +125,7 @@ std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds)
plane.dist = -bounds.mins()[i]; plane.dist = -bounds.mins()[i];
side_t &side = b->sides[3 + i]; side_t &side = b->sides[3 + i];
side.plane_flipped = side.plane.set_plane(plane, true); side.planenum = map.add_or_find_plane(plane);
} }
} }
@ -274,7 +274,7 @@ TestBrushToPlanenum
============ ============
*/ */
static int TestBrushToPlanenum( static int TestBrushToPlanenum(
const bspbrush_t &brush, const qbsp_plane_t &plane, int *numsplits, bool *hintsplit, int *epsilonbrush) const bspbrush_t &brush, size_t planenum, int *numsplits, bool *hintsplit, int *epsilonbrush)
{ {
if (numsplits) { if (numsplits) {
*numsplits = 0; *numsplits = 0;
@ -286,17 +286,16 @@ static int TestBrushToPlanenum(
// if the brush actually uses the planenum, // if the brush actually uses the planenum,
// we can tell the side for sure // we can tell the side for sure
for (auto &side : brush.sides) { for (auto &side : brush.sides) {
if (qv::epsilonEqual(side.plane, plane)) { if (side.planenum == planenum) {
if (side.plane_flipped == SIDE_FRONT) { return PSIDE_BACK | PSIDE_FACING;
return PSIDE_BACK | PSIDE_FACING; } else if (side.planenum == (planenum ^ 1)) {
} else { return PSIDE_FRONT|PSIDE_FACING;
return PSIDE_FRONT | PSIDE_FACING;
}
} }
} }
// box on plane side // box on plane side
// int s = SphereOnPlaneSide(brush.sphere_origin, brush.sphere_radius, plane); // int s = SphereOnPlaneSide(brush.sphere_origin, brush.sphere_radius, plane);
const qbsp_plane_t &plane = map.get_plane(planenum);
int s = BoxOnPlaneSide(brush.bounds, plane); int s = BoxOnPlaneSide(brush.bounds, plane);
if (s != PSIDE_BOTH) if (s != PSIDE_BOTH)
return s; return s;
@ -589,7 +588,7 @@ static twosided<std::unique_ptr<bspbrush_t>> SplitBrush(std::unique_ptr<bspbrush
// for the brush on the front side of the plane, the `midwinding` // for the brush on the front side of the plane, the `midwinding`
// (the face that is touching the plane) should have a normal opposite the plane's normal // (the face that is touching the plane) should have a normal opposite the plane's normal
cs.plane_flipped = cs.plane.set_plane(brushOnFront ? -split : split, true); cs.planenum = map.find_plane(split) ^ i ^ 1;
cs.texinfo = map.skip_texinfo; cs.texinfo = map.skip_texinfo;
cs.visible = false; cs.visible = false;
cs.tested = false; cs.tested = false;
@ -712,13 +711,13 @@ 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 node_t *node) static std::optional<size_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<size_t> bestaxialplane;
vec_t bestanymetric = VECT_MAX; vec_t bestanymetric = VECT_MAX;
std::optional<qbsp_plane_t> bestanyplane; std::optional<size_t> bestanyplane;
for (auto &brush : brushes) { for (auto &brush : brushes) {
for (auto &side : brush->sides) { for (auto &side : brush->sides) {
@ -729,7 +728,7 @@ static std::optional<qbsp_plane_t> ChooseMidPlaneFromList(const std::vector<std:
continue; // allready a node splitter continue; // allready a node splitter
} }
const qbsp_plane_t &plane = side.plane; const qbsp_plane_t &plane = side.get_positive_plane();
if (!CheckPlaneAgainstVolume(plane, node)) { if (!CheckPlaneAgainstVolume(plane, node)) {
continue; // would produce a tiny volume continue; // would produce a tiny volume
@ -740,14 +739,14 @@ static std::optional<qbsp_plane_t> ChooseMidPlaneFromList(const std::vector<std:
if (metric < bestanymetric) { if (metric < bestanymetric) {
bestanymetric = metric; bestanymetric = metric;
bestanyplane = plane; bestanyplane = side.planenum & ~1;
} }
/* check for axis aligned surfaces */ /* check for axis aligned surfaces */
if (plane.get_type() < plane_type_t::PLANE_ANYX) { if (plane.get_type() < plane_type_t::PLANE_ANYX) {
if (metric < bestaxialmetric) { if (metric < bestaxialmetric) {
bestaxialmetric = metric; bestaxialmetric = metric;
bestaxialplane = plane; bestaxialplane = side.planenum & ~1;
} }
} }
} }
@ -766,7 +765,7 @@ 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, std::optional<bool> forced_quick_tree, bspstats_t &stats) static std::optional<size_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()) {
@ -776,6 +775,7 @@ static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::uniqu
// if forced_quick_tree is nullopt, we will choose fast/slow based on // if forced_quick_tree is nullopt, we will choose fast/slow based on
// certain parameters. // certain parameters.
if (!forced_quick_tree.has_value() || forced_quick_tree.value() == true) { if (!forced_quick_tree.has_value() || forced_quick_tree.value() == true) {
#if 0
// if it is crossing a block boundary, force a split; // if it is crossing a block boundary, force a split;
// this is optional q3map2 mode that is disabled by default. // this is optional q3map2 mode that is disabled by default.
if (qbsp_options.blocksize.isChanged()) { if (qbsp_options.blocksize.isChanged()) {
@ -806,6 +806,7 @@ static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::uniqu
} }
} }
} }
#endif
if (!forced_quick_tree.has_value()) { if (!forced_quick_tree.has_value()) {
@ -869,7 +870,7 @@ static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::uniqu
if (side.visible ^ (pass < 2)) if (side.visible ^ (pass < 2))
continue; // only check visible faces on first pass continue; // only check visible faces on first pass
qbsp_plane_t plane(side.plane, true); // always use positive facing plane const qbsp_plane_t &plane = side.get_positive_plane(); // always use positive facing plane
CheckPlaneAgainstParents(plane, node); CheckPlaneAgainstParents(plane, node);
@ -886,7 +887,7 @@ static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::uniqu
for (auto &test : brushes) { for (auto &test : brushes) {
int bsplits; int bsplits;
int s = TestBrushToPlanenum(*test, plane, &bsplits, &hintsplit, &epsilonbrush); int s = TestBrushToPlanenum(*test, side.planenum & ~1, &bsplits, &hintsplit, &epsilonbrush);
splits += bsplits; splits += bsplits;
if (bsplits && (s & PSIDE_FACING)) if (bsplits && (s & PSIDE_FACING))
@ -898,7 +899,7 @@ static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::uniqu
if (s & PSIDE_FACING) { if (s & PSIDE_FACING) {
facing++; facing++;
for (auto &testside : test->sides) { for (auto &testside : test->sides) {
if (qv::epsilonEqual(testside.plane, plane)) { if ((testside.planenum & ~1) == (side.planenum & ~1)) {
testside.tested = true; testside.tested = true;
} }
} }
@ -966,7 +967,7 @@ static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::uniqu
stats.c_qbsp3++; stats.c_qbsp3++;
return bestside->plane; return bestside->planenum & ~1;
} }
/* /*
@ -1001,7 +1002,7 @@ static std::array<std::vector<std::unique_ptr<bspbrush_t>>, 2> SplitBrushList(
// as a splitter again // as a splitter again
if (sides & PSIDE_FACING) { if (sides & PSIDE_FACING) {
for (auto &side : brush->sides) { for (auto &side : brush->sides) {
if (qv::epsilonEqual(side.plane, plane)) { if (qv::epsilonEqual(side.get_positive_plane(), plane)) {
side.onnode = true; side.onnode = true;
} }
} }
@ -1045,7 +1046,11 @@ static void BuildTree_r(node_t *node, std::vector<std::unique_ptr<bspbrush_t>> b
// this is a splitplane node // this is a splitplane node
stats.c_nodes++; stats.c_nodes++;
node->plane.set_plane(bestplane.value(), true); // always use front facing // make sure this was a positive-facing split
Q_assert(!(bestplane.value() & 1));
auto &plane = map.get_plane(bestplane.value());
node->plane.set_plane(plane);
auto children = SplitBrushList(std::move(brushes), node->plane); auto children = SplitBrushList(std::move(brushes), node->plane);
@ -1057,9 +1062,9 @@ static void BuildTree_r(node_t *node, std::vector<std::unique_ptr<bspbrush_t>> b
} }
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (bestplane->get_normal()[i] == 1.0) { if (plane.get_normal()[i] == 1.0) {
node->children[0]->bounds[0][i] = bestplane->get_dist(); node->children[0]->bounds[0][i] = plane.get_dist();
node->children[1]->bounds[1][i] = bestplane->get_dist(); node->children[1]->bounds[1][i] = plane.get_dist();
break; break;
} }
} }

View File

@ -479,8 +479,8 @@ static std::unique_ptr<face_t> FaceFromPortal(portal_t *p, bool pside)
auto f = std::make_unique<face_t>(); auto f = std::make_unique<face_t>();
f->texinfo = side->texinfo; f->texinfo = side->texinfo;
f->plane = side->plane; f->plane = side->get_positive_plane();
f->plane_flipped = pside; f->plane_flipped = side->planenum & 1;
f->portal = p; f->portal = p;
f->lmshift = side->lmshift; f->lmshift = side->lmshift;

View File

@ -2095,6 +2095,7 @@ void LoadMapFile(void)
logging::print(logging::flag::STAT, " {:8} entities\n", map.entities.size()); logging::print(logging::flag::STAT, " {:8} entities\n", map.entities.size());
logging::print(logging::flag::STAT, " {:8} unique texnames\n", map.miptex.size()); logging::print(logging::flag::STAT, " {:8} unique texnames\n", map.miptex.size());
logging::print(logging::flag::STAT, " {:8} texinfo\n", map.mtexinfos.size()); logging::print(logging::flag::STAT, " {:8} texinfo\n", map.mtexinfos.size());
logging::print(logging::flag::STAT, " {:8} unique planes\n", map.planes.size());
logging::print(logging::flag::STAT, "\n"); logging::print(logging::flag::STAT, "\n");
if (qbsp_options.expand.value()) { if (qbsp_options.expand.value()) {
@ -2443,7 +2444,7 @@ void WriteBspBrushMap(const fs::path &name, const std::vector<std::unique_ptr<bs
fmt::print(f, "{{\n"); fmt::print(f, "{{\n");
for (auto &face : brush->sides) { for (auto &face : brush->sides) {
// FIXME: Factor out this mess // FIXME: Factor out this mess
winding_t w = BaseWindingForPlane(face.plane_flipped ? -face.plane : face.plane); winding_t w = BaseWindingForPlane(face.get_plane());
fmt::print(f, "( {} ) ", w[0]); fmt::print(f, "( {} ) ", w[0]);
fmt::print(f, "( {} ) ", w[1]); fmt::print(f, "( {} ) ", w[1]);

View File

@ -411,7 +411,8 @@ static void MarkVisibleBrushSides_R(node_t *node)
// leaf that are coplanar // leaf that are coplanar
for (auto *brush : neighbour_leaf->original_brushes) { for (auto *brush : neighbour_leaf->original_brushes) {
for (auto &side : brush->sides) { for (auto &side : brush->sides) {
if (qv::epsilonEqual(side.plane, portal->plane)) { //if (qv::epsilonEqual(side.plane, portal->plane)) {
if (qv::epsilonEqual(side.get_positive_plane(), portal->plane)) {
// we've found a brush side in an original brush in the neighbouring // we've found a brush side in an original brush in the neighbouring
// leaf, on a portal to this (non-opaque) leaf, so mark it as visible. // leaf, on a portal to this (non-opaque) leaf, so mark it as visible.
side.visible = true; side.visible = true;

View File

@ -816,11 +816,11 @@ static void FindPortalSide(portal_t *p)
// fixme-brushbsp: restore // fixme-brushbsp: restore
// if (!side.visible) // if (!side.visible)
// continue; // non-visible // continue; // non-visible
if (qv::epsilonEqual(side.plane, p1)) { if (qv::epsilonEqual(side.get_positive_plane(), p1)) {
// exact match (undirectional) // exact match (undirectional)
// because the brush is on j of the positive plane, the brushside must be facing away from j // because the brush is on j of the positive plane, the brushside must be facing away from j
Q_assert(side.plane_flipped == !j); Q_assert((side.planenum & 1) == !j);
// see which way(s) we want to generate faces - we could be a brush on either side of // see which way(s) we want to generate faces - we could be a brush on either side of
// the portal, generating either a outward face (common case) or an inward face (liquids) or both. // the portal, generating either a outward face (common case) or an inward face (liquids) or both.

View File

@ -316,7 +316,7 @@ static std::vector<std::tuple<size_t, const side_t *>> AddBrushBevels(const bspb
std::vector<std::tuple<size_t, const side_t *>> planes; std::vector<std::tuple<size_t, const side_t *>> planes;
for (auto &f : b.sides) { for (auto &f : b.sides) {
qplane3d plane = f.plane_flipped ? -f.plane : f.plane; const qplane3d &plane = f.get_plane();
int32_t outputplanenum = ExportMapPlane(plane); int32_t outputplanenum = ExportMapPlane(plane);
planes.emplace_back(outputplanenum, &f); planes.emplace_back(outputplanenum, &f);
} }
@ -398,7 +398,7 @@ static std::vector<std::tuple<size_t, const side_t *>> AddBrushBevels(const bspb
// behind this plane, it is a proper edge bevel // behind this plane, it is a proper edge bevel
for (; it != b.sides.end(); it++) { for (; it != b.sides.end(); it++) {
auto &f = *it; auto &f = *it;
qplane3d plane = f.plane_flipped ? -f.plane : f.plane; const qplane3d &plane = f.get_plane();
// if this plane has allready been used, skip it // if this plane has allready been used, skip it
if (qv::epsilonEqual(current, plane)) if (qv::epsilonEqual(current, plane))
@ -776,7 +776,7 @@ static void BSPX_Brushes_AddModel(
permodel.numbrushes++; permodel.numbrushes++;
for (auto &f : b->sides) { for (auto &f : b->sides) {
/*skip axial*/ /*skip axial*/
const auto &plane = f.plane; const auto &plane = f.get_plane();
if (plane.get_type() < plane_type_t::PLANE_ANYX) if (plane.get_type() < plane_type_t::PLANE_ANYX)
continue; continue;
permodel.numfaces++; permodel.numfaces++;
@ -794,7 +794,7 @@ static void BSPX_Brushes_AddModel(
for (auto &f : b->sides) { for (auto &f : b->sides) {
/*skip axial*/ /*skip axial*/
const auto &plane = f.plane; const auto &plane = f.get_plane();
if (plane.get_type() < plane_type_t::PLANE_ANYX) if (plane.get_type() < plane_type_t::PLANE_ANYX)
continue; continue;
perbrush.numfaces++; perbrush.numfaces++;
@ -835,18 +835,11 @@ static void BSPX_Brushes_AddModel(
for (auto &f : b->sides) { for (auto &f : b->sides) {
/*skip axial*/ /*skip axial*/
const auto &plane = f.plane; const auto &plane = f.get_plane();
if (plane.get_type() < plane_type_t::PLANE_ANYX) if (plane.get_type() < plane_type_t::PLANE_ANYX)
continue; continue;
bspxbrushes_perface perface; bspxbrushes_perface perface = qplane3f(plane.get_normal(), plane.get_dist());
if (f.plane_flipped) {
perface = -plane.get_plane();
} else {
perface = plane.get_plane();
}
str <= std::tie(perface.normal, perface.dist); str <= std::tie(perface.normal, perface.dist);
} }
} }