qbsp_plane_t is now used by other structures, and contains a faster epsilonEqual; since the majority of planes (especially nodes) are going to be axial, there's no need to use the slower full comparison when we can check if the axial component is ready.
This commit is contained in:
parent
c5d0c4dc67
commit
146f20f677
|
|
@ -37,71 +37,6 @@
|
|||
|
||||
struct bspbrush_t;
|
||||
|
||||
struct qbsp_plane_t : qplane3d
|
||||
{
|
||||
plane_type_t type = plane_type_t::PLANE_INVALID;
|
||||
|
||||
[[nodiscard]] constexpr qbsp_plane_t operator-() const { return {qplane3d::operator-(), type}; }
|
||||
|
||||
// create a qbsp_plane_t from a plane.
|
||||
// if flip is true, the returned plane will only be positive.
|
||||
static inline qbsp_plane_t from_plane(const qplane3d &plane, bool flip, bool &was_flipped)
|
||||
{
|
||||
was_flipped = false;
|
||||
qbsp_plane_t p { plane };
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
if (p.normal[i] == 1.0) {
|
||||
p.normal[(i + 1) % 3] = 0;
|
||||
p.normal[(i + 2) % 3] = 0;
|
||||
p.type = (i == 0 ? plane_type_t::PLANE_X : i == 1 ? plane_type_t::PLANE_Y : plane_type_t::PLANE_Z);
|
||||
return p;
|
||||
}
|
||||
if (p.normal[i] == -1.0) {
|
||||
if (flip) {
|
||||
p.normal[i] = 1.0;
|
||||
p.dist = -p.dist;
|
||||
was_flipped = true;
|
||||
}
|
||||
p.normal[(i + 1) % 3] = 0;
|
||||
p.normal[(i + 2) % 3] = 0;
|
||||
p.type = (i == 0 ? plane_type_t::PLANE_X : i == 1 ? plane_type_t::PLANE_Y : plane_type_t::PLANE_Z);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
vec_t ax = fabs(p.normal[0]);
|
||||
vec_t ay = fabs(p.normal[1]);
|
||||
vec_t az = fabs(p.normal[2]);
|
||||
|
||||
size_t nearest;
|
||||
|
||||
if (ax >= ay && ax >= az) {
|
||||
nearest = 0;
|
||||
p.type = plane_type_t::PLANE_ANYX;
|
||||
} else if (ay >= ax && ay >= az) {
|
||||
nearest = 1;
|
||||
p.type = plane_type_t::PLANE_ANYY;
|
||||
} else {
|
||||
nearest = 2;
|
||||
p.type = plane_type_t::PLANE_ANYZ;
|
||||
}
|
||||
|
||||
if (flip && p.normal[nearest] < 0) {
|
||||
was_flipped = true;
|
||||
return -p;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline qbsp_plane_t from_plane(const qplane3d &plane, bool flip = false)
|
||||
{
|
||||
bool unused;
|
||||
return from_plane(plane, flip, unused);
|
||||
}
|
||||
};
|
||||
|
||||
struct mapface_t
|
||||
{
|
||||
qbsp_plane_t plane{};
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ struct tree_t;
|
|||
|
||||
struct portal_t
|
||||
{
|
||||
qplane3d plane;
|
||||
qbsp_plane_t plane;
|
||||
node_t *onnode; // nullptr = portal to the outside of the world (one of six sides of a box)
|
||||
node_t *nodes[2]; // [0] = front side of planenum
|
||||
portal_t *next[2]; // [0] = next portal in nodes[0]'s list of portals
|
||||
|
|
|
|||
|
|
@ -379,6 +379,145 @@ struct face_t
|
|||
portal_t *portal;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct qbsp_plane_t : qplane3d
|
||||
{
|
||||
plane_type_t type = plane_type_t::PLANE_INVALID;
|
||||
|
||||
qbsp_plane_t() = default;
|
||||
qbsp_plane_t(const qbsp_plane_t &) = default;
|
||||
constexpr qbsp_plane_t(const qplane3d &plane, const plane_type_t &type) noexcept :
|
||||
qplane3d(plane),
|
||||
type(type)
|
||||
{
|
||||
}
|
||||
inline qbsp_plane_t(const qplane3d &plane) noexcept :
|
||||
qbsp_plane_t(plane, calculate_type(plane))
|
||||
{
|
||||
}
|
||||
|
||||
qbsp_plane_t &operator=(const qbsp_plane_t &) = default;
|
||||
inline qbsp_plane_t &operator=(const qplane3d &plane) noexcept
|
||||
{
|
||||
return *this = from_plane(plane);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr qbsp_plane_t operator-() const { return {qplane3d::operator-(), type}; }
|
||||
|
||||
// create a qbsp_plane_t from a plane.
|
||||
// if flip is true, the returned plane will only be positive.
|
||||
static inline qbsp_plane_t from_plane(const qplane3d &plane, bool flip, bool &was_flipped) noexcept
|
||||
{
|
||||
was_flipped = false;
|
||||
qbsp_plane_t p { plane };
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
if (p.normal[i] == 1.0) {
|
||||
p.normal[(i + 1) % 3] = 0;
|
||||
p.normal[(i + 2) % 3] = 0;
|
||||
p.type = (i == 0 ? plane_type_t::PLANE_X : i == 1 ? plane_type_t::PLANE_Y : plane_type_t::PLANE_Z);
|
||||
return p;
|
||||
}
|
||||
if (p.normal[i] == -1.0) {
|
||||
if (flip) {
|
||||
p.normal[i] = 1.0;
|
||||
p.dist = -p.dist;
|
||||
was_flipped = true;
|
||||
}
|
||||
p.normal[(i + 1) % 3] = 0;
|
||||
p.normal[(i + 2) % 3] = 0;
|
||||
p.type = (i == 0 ? plane_type_t::PLANE_X : i == 1 ? plane_type_t::PLANE_Y : plane_type_t::PLANE_Z);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
vec_t ax = fabs(p.normal[0]);
|
||||
vec_t ay = fabs(p.normal[1]);
|
||||
vec_t az = fabs(p.normal[2]);
|
||||
|
||||
size_t nearest;
|
||||
|
||||
if (ax >= ay && ax >= az) {
|
||||
nearest = 0;
|
||||
p.type = plane_type_t::PLANE_ANYX;
|
||||
} else if (ay >= ax && ay >= az) {
|
||||
nearest = 1;
|
||||
p.type = plane_type_t::PLANE_ANYY;
|
||||
} else {
|
||||
nearest = 2;
|
||||
p.type = plane_type_t::PLANE_ANYZ;
|
||||
}
|
||||
|
||||
if (flip && p.normal[nearest] < 0) {
|
||||
was_flipped = true;
|
||||
return -p;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline qbsp_plane_t from_plane(const qplane3d &plane, bool flip = false)
|
||||
{
|
||||
bool unused;
|
||||
return from_plane(plane, flip, unused);
|
||||
}
|
||||
|
||||
static inline plane_type_t calculate_type(const qplane3d &p)
|
||||
{
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
if (p.normal[i] == 1.0 || p.normal[i] == -1.0) {
|
||||
return (i == 0 ? plane_type_t::PLANE_X : i == 1 ? plane_type_t::PLANE_Y : plane_type_t::PLANE_Z);
|
||||
}
|
||||
}
|
||||
|
||||
vec_t ax = fabs(p.normal[0]);
|
||||
vec_t ay = fabs(p.normal[1]);
|
||||
vec_t az = fabs(p.normal[2]);
|
||||
|
||||
if (ax >= ay && ax >= az) {
|
||||
return plane_type_t::PLANE_ANYX;
|
||||
} else if (ay >= ax && ay >= az) {
|
||||
return plane_type_t::PLANE_ANYY;
|
||||
} else {
|
||||
return plane_type_t::PLANE_ANYZ;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace qv
|
||||
{
|
||||
// faster version of epsilonEqual for BSP planes
|
||||
// which have a bit more info in them
|
||||
[[nodiscard]] inline bool epsilonEqual(const qbsp_plane_t &p1, const qbsp_plane_t &p2, vec_t normalEpsilon = NORMAL_EPSILON, vec_t distEpsilon = DIST_EPSILON)
|
||||
{
|
||||
Q_assert(p1.type != plane_type_t::PLANE_INVALID);
|
||||
Q_assert(p2.type != plane_type_t::PLANE_INVALID);
|
||||
|
||||
// axial planes will never match on normal, so we can skip that check entirely
|
||||
if (p1.type < plane_type_t::PLANE_ANYX && p2.type < plane_type_t::PLANE_ANYX) {
|
||||
// if we aren't the same type, we definitely aren't equal
|
||||
if (p1.type != p2.type) {
|
||||
return false;
|
||||
} else if (p1.normal[static_cast<int32_t>(p1.type)] != p2.normal[static_cast<int32_t>(p2.type)]) {
|
||||
// axials will always be only 1 or -1
|
||||
return false;
|
||||
}
|
||||
|
||||
// check dist
|
||||
return epsilonEqual(p1.dist, p2.dist, distEpsilon);
|
||||
}
|
||||
|
||||
// check dist
|
||||
if (!epsilonEqual(p1.dist, p2.dist, distEpsilon)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check normal
|
||||
return epsilonEqual(p1.normal, p2.normal, normalEpsilon);
|
||||
}
|
||||
}; // namespace qv
|
||||
|
||||
// there is a node_t structure for every node and leaf in the bsp tree
|
||||
|
||||
struct bspbrush_t;
|
||||
|
|
@ -394,7 +533,7 @@ struct node_t
|
|||
bool is_leaf = false;
|
||||
|
||||
// information for decision nodes
|
||||
qplane3d plane; // decision node only
|
||||
qbsp_plane_t plane; // decision node only
|
||||
int firstface; // decision node only
|
||||
int numfaces; // decision node only
|
||||
twosided<std::unique_ptr<node_t>> children; // children[0] = front side, children[1] = back side of plane. only valid for decision nodes
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ This is done by brute force, and could easily get a lot faster if anyone cares.
|
|||
AddBrushPlane
|
||||
=============
|
||||
*/
|
||||
static void AddBrushPlane(hullbrush_t *hullbrush, const qplane3d &plane)
|
||||
static void AddBrushPlane(hullbrush_t *hullbrush, const qbsp_plane_t &plane)
|
||||
{
|
||||
vec_t len = qv::length(plane.normal);
|
||||
|
||||
|
|
@ -382,8 +382,7 @@ static void AddBrushPlane(hullbrush_t *hullbrush, const qplane3d &plane)
|
|||
FError("invalid normal (vector length {:.4})", len);
|
||||
|
||||
for (auto &mapface : hullbrush->faces) {
|
||||
if (qv::epsilonEqual(mapface.plane.normal, plane.normal, EQUAL_EPSILON) &&
|
||||
fabs(mapface.plane.dist - plane.dist) < qbsp_options.epsilon.value())
|
||||
if (qv::epsilonEqual(mapface.plane, plane, EQUAL_EPSILON, qbsp_options.epsilon.value()))
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -404,7 +403,7 @@ Adds the given plane to the brush description if all of the original brush
|
|||
vertexes can be put on the front side
|
||||
=============
|
||||
*/
|
||||
static void TestAddPlane(hullbrush_t *hullbrush, qplane3d &plane)
|
||||
static void TestAddPlane(hullbrush_t *hullbrush, qbsp_plane_t &plane)
|
||||
{
|
||||
vec_t d;
|
||||
int points_front, points_back;
|
||||
|
|
@ -483,7 +482,7 @@ static void AddHullEdge(hullbrush_t *hullbrush, const qvec3d &p1, const qvec3d &
|
|||
{
|
||||
int pt1, pt2;
|
||||
int a, b, c, d, e;
|
||||
qplane3d plane;
|
||||
qbsp_plane_t plane;
|
||||
vec_t length;
|
||||
|
||||
pt1 = AddHullPoint(hullbrush, p1, hull_size);
|
||||
|
|
@ -523,6 +522,7 @@ static void AddHullEdge(hullbrush_t *hullbrush, const qvec3d &p1, const qvec3d &
|
|||
planeorg[b] += hull_size[d][b];
|
||||
planeorg[c] += hull_size[e][c];
|
||||
plane.dist = qv::dot(planeorg, plane.normal);
|
||||
plane.type = qbsp_plane_t::calculate_type(plane);
|
||||
TestAddPlane(hullbrush, plane);
|
||||
}
|
||||
}
|
||||
|
|
@ -575,6 +575,7 @@ static void ExpandBrush(hullbrush_t *hullbrush, const aabb3d &hull_size, std::ve
|
|||
plane.dist = -hullbrush->bounds.mins()[x] + -hull_size[0][x];
|
||||
else
|
||||
plane.dist = hullbrush->bounds.maxs()[x] + hull_size[1][x];
|
||||
plane.type = qbsp_plane_t::calculate_type(plane);
|
||||
AddBrushPlane(hullbrush, plane);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1531,6 +1531,7 @@ bool mapface_t::set_planepts(const std::array<qvec3d, 3> &pts)
|
|||
|
||||
plane.normal = qv::normalize(qv::cross(ab, cb), length);
|
||||
plane.dist = qv::dot(planepts[1], plane.normal);
|
||||
plane.type = qbsp_plane_t::calculate_type(plane);
|
||||
|
||||
return length >= NORMAL_EPSILON;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ void MakeHeadnodePortals(tree_t *tree)
|
|||
{
|
||||
int i, j, n;
|
||||
portal_t *p, *portals[6];
|
||||
qbsp_plane_t bplanes[6];
|
||||
qplane3d bplanes[6];
|
||||
|
||||
// pad with some space so there will never be null volume leafs
|
||||
aabb3d bounds = tree->bounds.grow(SIDESPACE);
|
||||
|
|
@ -726,7 +726,7 @@ static void FindPortalSide(portal_t *p)
|
|||
// bestside[0] is the brushside visible on portal side[0] which is the positive side of the plane, always
|
||||
side_t *bestside[2] = {nullptr, nullptr};
|
||||
float bestdot = 0;
|
||||
const qplane3d &p1 = p->onnode->plane;
|
||||
const qbsp_plane_t &p1 = p->onnode->plane;
|
||||
|
||||
// check brushes on both sides of the portal
|
||||
for (int j = 0; j < 2; j++)
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ static mapplane_t &NewPlane(const qplane3d &plane)
|
|||
return added_plane;
|
||||
}
|
||||
|
||||
static mapplane_t &FindPlane(const qplane3d &plane)
|
||||
static mapplane_t &FindPlane(const qbsp_plane_t &plane)
|
||||
{
|
||||
for (int i : map.planehash[plane_hash_fn(plane)]) {
|
||||
mapplane_t &p = map.planes.at(i);
|
||||
|
|
|
|||
Loading…
Reference in New Issue