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

View File

@ -164,6 +164,19 @@ struct mapdata_t
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
// return a new one
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];
}
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
{
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)
{
if (face->plane_flipped) {
return -face->plane;
}
return face->plane;
return face->get_plane();
}
/*
@ -96,8 +102,6 @@ Note: this will not catch 0 area polygons
*/
static void CheckFace(side_t *face, const mapface_t &sourceface)
{
const qplane3d &plane = face->plane;
if (face->w.size() < 3) {
if (face->w.size() == 2) {
logging::print(
@ -112,11 +116,8 @@ static void CheckFace(side_t *face, const mapface_t &sourceface)
return;
}
qvec3d facenormal = plane.normal;
if (face->plane_flipped) {
facenormal = -facenormal;
}
const qbsp_plane_t &plane = face->get_plane();
qvec3d facenormal = plane.get_normal();
for (size_t i = 0; i < face->w.size(); 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);
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);
}

View File

@ -116,7 +116,7 @@ std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds)
plane.dist = bounds.maxs()[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];
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(
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) {
*numsplits = 0;
@ -286,17 +286,16 @@ static int TestBrushToPlanenum(
// if the brush actually uses the planenum,
// we can tell the side for sure
for (auto &side : brush.sides) {
if (qv::epsilonEqual(side.plane, plane)) {
if (side.plane_flipped == SIDE_FRONT) {
return PSIDE_BACK | PSIDE_FACING;
} else {
return PSIDE_FRONT | PSIDE_FACING;
}
if (side.planenum == planenum) {
return PSIDE_BACK | PSIDE_FACING;
} else if (side.planenum == (planenum ^ 1)) {
return PSIDE_FRONT|PSIDE_FACING;
}
}
// box on plane side
// 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);
if (s != PSIDE_BOTH)
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`
// (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.visible = false;
cs.tested = false;
@ -712,13 +711,13 @@ ChooseMidPlaneFromList
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;
std::optional<qbsp_plane_t> bestaxialplane;
std::optional<size_t> bestaxialplane;
vec_t bestanymetric = VECT_MAX;
std::optional<qbsp_plane_t> bestanyplane;
std::optional<size_t> bestanyplane;
for (auto &brush : brushes) {
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
}
const qbsp_plane_t &plane = side.plane;
const qbsp_plane_t &plane = side.get_positive_plane();
if (!CheckPlaneAgainstVolume(plane, node)) {
continue; // would produce a tiny volume
@ -740,14 +739,14 @@ static std::optional<qbsp_plane_t> ChooseMidPlaneFromList(const std::vector<std:
if (metric < bestanymetric) {
bestanymetric = metric;
bestanyplane = plane;
bestanyplane = side.planenum & ~1;
}
/* check for axis aligned surfaces */
if (plane.get_type() < plane_type_t::PLANE_ANYX) {
if (metric < bestaxialmetric) {
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.
================
*/
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.
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
// certain parameters.
if (!forced_quick_tree.has_value() || forced_quick_tree.value() == true) {
#if 0
// if it is crossing a block boundary, force a split;
// this is optional q3map2 mode that is disabled by default.
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()) {
@ -869,7 +870,7 @@ static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::uniqu
if (side.visible ^ (pass < 2))
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);
@ -886,7 +887,7 @@ static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::uniqu
for (auto &test : brushes) {
int bsplits;
int s = TestBrushToPlanenum(*test, plane, &bsplits, &hintsplit, &epsilonbrush);
int s = TestBrushToPlanenum(*test, side.planenum & ~1, &bsplits, &hintsplit, &epsilonbrush);
splits += bsplits;
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) {
facing++;
for (auto &testside : test->sides) {
if (qv::epsilonEqual(testside.plane, plane)) {
if ((testside.planenum & ~1) == (side.planenum & ~1)) {
testside.tested = true;
}
}
@ -966,7 +967,7 @@ static std::optional<qbsp_plane_t> SelectSplitPlane(const std::vector<std::uniqu
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
if (sides & PSIDE_FACING) {
for (auto &side : brush->sides) {
if (qv::epsilonEqual(side.plane, plane)) {
if (qv::epsilonEqual(side.get_positive_plane(), plane)) {
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
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);
@ -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++) {
if (bestplane->get_normal()[i] == 1.0) {
node->children[0]->bounds[0][i] = bestplane->get_dist();
node->children[1]->bounds[1][i] = bestplane->get_dist();
if (plane.get_normal()[i] == 1.0) {
node->children[0]->bounds[0][i] = plane.get_dist();
node->children[1]->bounds[1][i] = plane.get_dist();
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>();
f->texinfo = side->texinfo;
f->plane = side->plane;
f->plane_flipped = pside;
f->plane = side->get_positive_plane();
f->plane_flipped = side->planenum & 1;
f->portal = p;
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} unique texnames\n", map.miptex.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");
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");
for (auto &face : brush->sides) {
// 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[1]);

View File

@ -411,7 +411,8 @@ static void MarkVisibleBrushSides_R(node_t *node)
// leaf that are coplanar
for (auto *brush : neighbour_leaf->original_brushes) {
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
// leaf, on a portal to this (non-opaque) leaf, so mark it as visible.
side.visible = true;

View File

@ -816,11 +816,11 @@ static void FindPortalSide(portal_t *p)
// fixme-brushbsp: restore
// if (!side.visible)
// continue; // non-visible
if (qv::epsilonEqual(side.plane, p1)) {
if (qv::epsilonEqual(side.get_positive_plane(), p1)) {
// exact match (undirectional)
// 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
// 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;
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);
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
for (; it != b.sides.end(); 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 (qv::epsilonEqual(current, plane))
@ -776,7 +776,7 @@ static void BSPX_Brushes_AddModel(
permodel.numbrushes++;
for (auto &f : b->sides) {
/*skip axial*/
const auto &plane = f.plane;
const auto &plane = f.get_plane();
if (plane.get_type() < plane_type_t::PLANE_ANYX)
continue;
permodel.numfaces++;
@ -794,7 +794,7 @@ static void BSPX_Brushes_AddModel(
for (auto &f : b->sides) {
/*skip axial*/
const auto &plane = f.plane;
const auto &plane = f.get_plane();
if (plane.get_type() < plane_type_t::PLANE_ANYX)
continue;
perbrush.numfaces++;
@ -835,18 +835,11 @@ static void BSPX_Brushes_AddModel(
for (auto &f : b->sides) {
/*skip axial*/
const auto &plane = f.plane;
const auto &plane = f.get_plane();
if (plane.get_type() < plane_type_t::PLANE_ANYX)
continue;
bspxbrushes_perface perface;
if (f.plane_flipped) {
perface = -plane.get_plane();
} else {
perface = plane.get_plane();
}
bspxbrushes_perface perface = qplane3f(plane.get_normal(), plane.get_dist());
str <= std::tie(perface.normal, perface.dist);
}
}