constexpr/inline qv:: where appropriate

comment out rewrite test in bspinfo
updated tjunc code
This commit is contained in:
Jonathan 2021-10-19 23:26:43 -04:00
parent 95b47db922
commit 1bf6261826
6 changed files with 130 additions and 268 deletions

View File

@ -339,7 +339,7 @@ int main(int argc, char **argv)
LoadBSPFile(source, &bsp);
PrintBSPFileSizes(&bsp);
WriteBSPFile(std::filesystem::path(source).replace_extension("bsp.rewrite"), &bsp);
//WriteBSPFile(std::filesystem::path(source).replace_extension("bsp.rewrite"), &bsp);
ConvertBSPFormat(&bsp, &bspver_generic);

View File

@ -270,13 +270,13 @@ struct fmt::formatter<qvec<T, N>> : formatter<T>
namespace qv
{
template<class T>
[[nodiscard]] qvec<T, 3> cross(const qvec<T, 3> &v1, const qvec<T, 3> &v2)
[[nodiscard]] constexpr qvec<T, 3> cross(const qvec<T, 3> &v1, const qvec<T, 3> &v2)
{
return qvec<T, 3>(v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]);
}
template<size_t N, class T>
[[nodiscard]] T dot(const qvec<T, N> &v1, const qvec<T, N> &v2)
[[nodiscard]] constexpr T dot(const qvec<T, N> &v1, const qvec<T, N> &v2)
{
T result = 0;
for (size_t i = 0; i < N; i++) {
@ -306,7 +306,7 @@ template<size_t N, class T>
}
template<size_t N, class T>
[[nodiscard]] T min(const qvec<T, N> &v)
[[nodiscard]] constexpr T min(const qvec<T, N> &v)
{
T res = std::numeric_limits<T>::largest();
for (auto &c : v) {
@ -316,7 +316,7 @@ template<size_t N, class T>
}
template<size_t N, class T>
[[nodiscard]] T max(const qvec<T, N> &v)
[[nodiscard]] constexpr T max(const qvec<T, N> &v)
{
T res = std::numeric_limits<T>::lowest();
for (auto &c : v) {
@ -326,7 +326,7 @@ template<size_t N, class T>
}
template<size_t N, class T>
[[nodiscard]] qvec<T, N> min(const qvec<T, N> &v1, const qvec<T, N> &v2)
[[nodiscard]] constexpr qvec<T, N> min(const qvec<T, N> &v1, const qvec<T, N> &v2)
{
qvec<T, N> res;
for (size_t i = 0; i < N; i++) {
@ -336,7 +336,7 @@ template<size_t N, class T>
}
template<size_t N, class T>
[[nodiscard]] qvec<T, N> max(const qvec<T, N> &v1, const qvec<T, N> &v2)
[[nodiscard]] constexpr qvec<T, N> max(const qvec<T, N> &v1, const qvec<T, N> &v2)
{
qvec<T, N> res;
for (size_t i = 0; i < N; i++) {
@ -346,7 +346,7 @@ template<size_t N, class T>
}
template<size_t N, class T>
[[nodiscard]] T length2(const qvec<T, N> &v1)
[[nodiscard]] constexpr T length2(const qvec<T, N> &v1)
{
T len2 = 0;
for (size_t i = 0; i < N; i++) {
@ -356,19 +356,19 @@ template<size_t N, class T>
}
template<size_t N, class T>
[[nodiscard]] T length(const qvec<T, N> &v1)
[[nodiscard]] inline T length(const qvec<T, N> &v1)
{
return std::sqrt(length2(v1));
}
template<size_t N, class T>
[[nodiscard]] qvec<T, N> normalize(const qvec<T, N> &v1)
[[nodiscard]] inline qvec<T, N> normalize(const qvec<T, N> &v1)
{
return v1 / length(v1);
}
template<size_t N, class T>
[[nodiscard]] T distance(const qvec<T, N> &v1, const qvec<T, N> &v2)
[[nodiscard]] inline T distance(const qvec<T, N> &v1, const qvec<T, N> &v2)
{
return length(v2 - v1);
}
@ -380,13 +380,13 @@ template<typename T>
}
template<typename T>
[[nodiscard]] bool epsilonEqual(const T &v1, const T &v2, T epsilon)
[[nodiscard]] inline bool epsilonEqual(const T &v1, const T &v2, T epsilon)
{
return fabs(v1 - v2) <= epsilon;
}
template<size_t N, class T>
[[nodiscard]] bool epsilonEqual(const qvec<T, N> &v1, const qvec<T, N> &v2, T epsilon)
[[nodiscard]] inline bool epsilonEqual(const qvec<T, N> &v1, const qvec<T, N> &v2, T epsilon)
{
for (size_t i = 0; i < N; i++) {
if (!epsilonEqual(v1[i], v2[i], epsilon))
@ -396,13 +396,13 @@ template<size_t N, class T>
}
template<size_t N, class T>
[[nodiscard]] bool epsilonEmpty(const qvec<T, N> &v1, T epsilon)
[[nodiscard]] inline bool epsilonEmpty(const qvec<T, N> &v1, T epsilon)
{
return epsilonEqual({}, v1, epsilon);
}
template<size_t N, class T>
[[nodiscard]] bool equalExact(const qvec<T, N> &v1, const qvec<T, N> &v2)
[[nodiscard]] constexpr bool equalExact(const qvec<T, N> &v1, const qvec<T, N> &v2)
{
for (size_t i = 0; i < N; i++) {
if (v1[i] != v2[i])
@ -412,13 +412,13 @@ template<size_t N, class T>
}
template<size_t N, class T>
[[nodiscard]] bool emptyExact(const qvec<T, N> &v1)
[[nodiscard]] constexpr bool emptyExact(const qvec<T, N> &v1)
{
return equalExact({}, v1);
}
template<size_t N, class T>
[[nodiscard]] size_t indexOfLargestMagnitudeComponent(const qvec<T, N> &v)
[[nodiscard]] inline size_t indexOfLargestMagnitudeComponent(const qvec<T, N> &v)
{
size_t largestIndex = 0;
T largestMag = 0;
@ -436,13 +436,13 @@ template<size_t N, class T>
}
template<size_t N, typename T>
[[nodiscard]] T TriangleArea(const qvec<T, N> &v0, const qvec<T, N> &v1, const qvec<T, N> &v2)
[[nodiscard]] inline T TriangleArea(const qvec<T, N> &v0, const qvec<T, N> &v1, const qvec<T, N> &v2)
{
return static_cast<T>(0.5) * qv::length(qv::cross(v2 - v0, v1 - v0));
}
template<typename Iter, typename T = typename std::iterator_traits<Iter>::value_type>
[[nodiscard]] T PolyCentroid(Iter begin, Iter end)
[[nodiscard]] inline T PolyCentroid(Iter begin, Iter end)
{
using value_type = typename T::value_type;
size_t num_points = end - begin;
@ -475,7 +475,7 @@ template<typename Iter, typename T = typename std::iterator_traits<Iter>::value_
}
template<typename Iter, typename T = typename std::iterator_traits<Iter>::value_type, typename F = typename T::value_type>
[[nodiscard]] F PolyArea(Iter begin, Iter end)
[[nodiscard]] inline F PolyArea(Iter begin, Iter end)
{
Q_assert((end - begin) >= 3);
@ -493,7 +493,7 @@ template<typename Iter, typename T = typename std::iterator_traits<Iter>::value_
}
template<typename T>
[[nodiscard]] qvec<T, 3> Barycentric_FromPoint(const qvec<T, 3> &p, const qvec<T, 3> &t0, const qvec<T, 3> &t1, const qvec<T, 3> &t2)
[[nodiscard]] inline qvec<T, 3> Barycentric_FromPoint(const qvec<T, 3> &p, const qvec<T, 3> &t0, const qvec<T, 3> &t1, const qvec<T, 3> &t2)
{
const auto v0 = t1 - t0;
const auto v1 = t2 - t0;
@ -515,7 +515,7 @@ template<typename T>
// from global illumination total compendium p. 12
template<typename T>
[[nodiscard]] qvec<T, 3> Barycentric_Random(T r1, T r2)
[[nodiscard]] inline qvec<T, 3> Barycentric_Random(T r1, T r2)
{
qvec<T, 3> res;
res[0] = 1.0 - sqrt(r1);
@ -526,14 +526,14 @@ template<typename T>
/// Evaluates the given barycentric coord for the given triangle
template<typename T>
[[nodiscard]] qvec<T, 3> Barycentric_ToPoint(const qvec<T, 3> &bary, const qvec<T, 3> &t0, const qvec<T, 3> &t1, const qvec<T, 3> &t2)
[[nodiscard]] constexpr qvec<T, 3> Barycentric_ToPoint(const qvec<T, 3> &bary, const qvec<T, 3> &t0, const qvec<T, 3> &t1, const qvec<T, 3> &t2)
{
return (t0 * bary[0]) + (t1 * bary[1]) + (t2 * bary[2]);
}
// Snap vector to nearest axial component
template<typename T>
[[nodiscard]] qvec<T, 3> Snap(qvec<T, 3> normal, const T &epsilon = NORMAL_EPSILON)
[[nodiscard]] inline qvec<T, 3> Snap(qvec<T, 3> normal, const T &epsilon = NORMAL_EPSILON)
{
for (auto &v : normal) {
if (fabs(v - 1) < epsilon) {

View File

@ -55,9 +55,6 @@
// Various other geometry maximums
constexpr size_t MAXEDGES = 64;
// don't let a base face get past this
// because it can be split more later
#define MAXPOINTS 60
// For brush.c, normal and +16 (?)
#define NUM_HULLS 2
@ -205,7 +202,6 @@ struct node_t
#include <qbsp/surfaces.hh>
#include <qbsp/portals.hh>
#include <qbsp/region.hh>
#include <qbsp/tjunc.hh>
#include <qbsp/writebsp.hh>
#include <qbsp/outside.hh>

View File

@ -1,36 +0,0 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 1997 Greg Lewis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
See file, 'COPYING', for details.
*/
#pragma once
struct wvert_t
{
vec_t t; /* t-value for parametric equation of edge */
wvert_t *prev, *next; /* t-ordered list of vertices on same edge */
};
struct wedge_t
{
wedge_t *next; /* pointer for hash bucket chain */
vec3_t dir; /* direction vector for the edge */
vec3_t origin; /* origin (t = 0) in parametric form */
wvert_t head; /* linked list of verticies on this edge */
};

View File

@ -12,7 +12,6 @@ set(QBSP_INCLUDES
${CMAKE_SOURCE_DIR}/include/qbsp/region.hh
${CMAKE_SOURCE_DIR}/include/qbsp/solidbsp.hh
${CMAKE_SOURCE_DIR}/include/qbsp/surfaces.hh
${CMAKE_SOURCE_DIR}/include/qbsp/tjunc.hh
${CMAKE_SOURCE_DIR}/include/qbsp/writebsp.hh)
set(QBSP_SOURCES

View File

@ -22,145 +22,112 @@
#include <qbsp/qbsp.hh>
static int numwedges, numwverts;
// don't let a base face get past this
// because it can be split more later
constexpr size_t MAXPOINTS = 60;
namespace qv
{
template<typename T>
[[nodiscard]] constexpr int32_t compareEpsilon(const T &v1, const T &v2, const T &epsilon)
{
T diff = v1 - v2;
return (diff > epsilon || diff < -epsilon) ? (diff < 0 ? -1 : 1) : 0;
}
template<typename T, size_t N>
[[nodiscard]] inline int32_t compareEpsilon(const qvec<T, N> &v1, const qvec<T, N> &v2, const T &epsilon)
{
for (size_t i = 0; i < N; i++) {
int32_t diff = compareEpsilon(v1[i], v2[i], epsilon);
if (diff) {
return diff;
}
}
return 0;
}
}
struct wedge_key_t
{
qvec3d dir; /* direction vector for the edge */
qvec3d origin; /* origin (t = 0) in parametric form */
inline bool operator<(const wedge_key_t &other) const
{
int32_t diff = qv::compareEpsilon(dir, other.dir, EQUAL_EPSILON);
if (diff) {
return diff < 0;
}
diff = qv::compareEpsilon(origin, other.origin, EQUAL_EPSILON);
if (diff) {
return diff < 0;
}
return false;
}
};
using wedge_t = std::list<vec_t>; /* linked list of vertices on this edge */
static int numwverts;
static int tjuncs;
static int tjuncfaces;
static int cWVerts;
static int cWEdges;
static wvert_t *pWVerts;
static wedge_t *pWEdges;
static std::map<wedge_key_t, wedge_t> pWEdges;
//============================================================================
#define NUM_HASH 1024
static wedge_t *wedge_hash[NUM_HASH];
static qvec3d hash_min, hash_scale;
static void InitHash(const qvec3d &mins, const qvec3d &maxs)
static qvec3d CanonicalVector(const qvec3d &p1, const qvec3d &p2)
{
vec_t volume;
vec_t scale;
int newsize[2];
hash_min = mins;
qvec3d size = maxs - mins;
memset(wedge_hash, 0, sizeof(wedge_hash));
volume = size[0] * size[1];
scale = sqrt(volume / NUM_HASH);
newsize[0] = (int)(size[0] / scale);
newsize[1] = (int)(size[1] / scale);
hash_scale[0] = newsize[0] / size[0];
hash_scale[1] = newsize[1] / size[1];
hash_scale[2] = (vec_t)newsize[1];
}
static unsigned HashVec(vec3_t vec)
{
unsigned h;
h = (unsigned)(hash_scale[0] * (vec[0] - hash_min[0]) * hash_scale[2] + hash_scale[1] * (vec[1] - hash_min[1]));
if (h >= NUM_HASH)
return NUM_HASH - 1;
return h;
}
//============================================================================
static void CanonicalVector(const qvec3d &p1, const qvec3d &p2, qvec3d &vec)
{
VectorSubtract(p2, p1, vec);
qvec3d vec = p2 - p1;
vec_t length = VectorNormalize(vec);
if (vec[0] > EQUAL_EPSILON)
return;
else if (vec[0] < -EQUAL_EPSILON) {
VectorInverse(vec);
return;
} else
vec[0] = 0;
if (vec[1] > EQUAL_EPSILON)
return;
else if (vec[1] < -EQUAL_EPSILON) {
VectorInverse(vec);
return;
} else
vec[1] = 0;
for (size_t i = 0; i < 3; i++) {
if (vec[i] > EQUAL_EPSILON) {
return vec;
} else if (vec[i] < -EQUAL_EPSILON) {
VectorInverse(vec);
return vec;
} else {
vec[i] = 0;
}
}
if (vec[2] > EQUAL_EPSILON)
return;
else if (vec[2] < -EQUAL_EPSILON) {
VectorInverse(vec);
return;
} else
vec[2] = 0;
LogPrint("WARNING: Line {}: Healing degenerate edge ({}) at ({:.3f} {:.3} {:.3})\n", length, p1[0], p1[1], p1[2]);
LogPrint("WARNING: Line {}: Healing degenerate edge ({}) at ({:.3}\n", length, vec);
return vec;
}
static wedge_t *FindEdge(const qvec3d &p1, const qvec3d &p2, vec_t &t1, vec_t &t2)
static std::pair<const wedge_key_t, wedge_t> &FindEdge(const qvec3d &p1, const qvec3d &p2, vec_t &t1, vec_t &t2)
{
qvec3d origin, edgevec;
wedge_t *edge;
int h;
CanonicalVector(p1, p2, edgevec);
qvec3d edgevec = CanonicalVector(p1, p2);
t1 = DotProduct(p1, edgevec);
t2 = DotProduct(p2, edgevec);
VectorMA(p1, -t1, edgevec, origin);
qvec3d origin = p1 + (edgevec * -t1);
if (t1 > t2) {
std::swap(t1, t2);
}
h = HashVec(&origin[0]);
wedge_key_t key { edgevec, origin };
auto it = pWEdges.find(key);
for (edge = wedge_hash[h]; edge; edge = edge->next) {
vec_t temp = edge->origin[0] - origin[0];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
temp = edge->origin[1] - origin[1];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
temp = edge->origin[2] - origin[2];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
temp = edge->dir[0] - edgevec[0];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
temp = edge->dir[1] - edgevec[1];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
temp = edge->dir[2] - edgevec[2];
if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON)
continue;
return edge;
if (it != pWEdges.end()) {
return *it;
}
if (numwedges >= cWEdges)
FError("Internal error: didn't allocate enough edges for tjuncs?");
edge = pWEdges + numwedges;
numwedges++;
auto &edge = pWEdges.emplace(key, wedge_t { }).first;
edge->next = wedge_hash[h];
wedge_hash[h] = edge;
edge->second.emplace_front(VECT_MAX);
VectorCopy(origin, edge->origin);
VectorCopy(edgevec, edge->dir);
edge->head.next = edge->head.prev = &edge->head;
edge->head.t = VECT_MAX;
return edge;
return *edge;
}
/*
@ -169,31 +136,21 @@ AddVert
===============
*/
static void AddVert(wedge_t *edge, vec_t t)
static void AddVert(wedge_t &edge, vec_t t)
{
wvert_t *v, *newv;
auto it = edge.begin();
v = edge->head.next;
do {
if (fabs(v->t - t) < T_EPSILON)
for (; it != edge.end(); it++) {
if (fabs(*it - t) < T_EPSILON) {
return;
if (v->t > t)
} else if (*it > t) {
break;
v = v->next;
} while (1);
}
}
// insert a new wvert before v
if (numwverts >= cWVerts)
FError("Internal error: didn't allocate enough vertices for tjuncs?");
newv = pWVerts + numwverts;
edge.insert(it, t);
numwverts++;
newv->t = t;
newv->next = v;
newv->prev = v->prev;
v->prev->next = newv;
v->prev = newv;
}
/*
@ -205,9 +162,9 @@ AddEdge
static void AddEdge(const qvec3d &p1, const qvec3d &p2)
{
vec_t t1, t2;
wedge_t *edge = FindEdge(p1, p2, t1, t2);
AddVert(edge, t1);
AddVert(edge, t2);
auto &edge = FindEdge(p1, p2, t1, t2);
AddVert(edge.second, t1);
AddVert(edge.second, t2);
}
/*
@ -330,24 +287,20 @@ FixFaceEdges
*/
static void FixFaceEdges(face_t *face, face_t *superface, face_t **facelist)
{
int i, j;
wedge_t *edge;
wvert_t *v;
vec_t t1, t2;
*superface = *face;
restart:
for (i = 0; i < superface->w.size(); i++) {
j = (i + 1) % superface->w.size();
for (size_t i = 0; i < superface->w.size(); i++) {
size_t j = (i + 1) % superface->w.size();
vec_t t1, t2;
auto &edge = FindEdge(superface->w[i], superface->w[j], t1, t2);
edge = FindEdge(superface->w[i], superface->w[j], t1, t2);
auto it = edge.second.begin();
while (*it < t1 + T_EPSILON)
it++;
v = edge->head.next;
while (v->t < t1 + T_EPSILON)
v = v->next;
if (v->t < t2 - T_EPSILON) {
if (*it < t2 - T_EPSILON) {
/* insert a new vertex here */
if (superface->w.size() == MAX_SUPERFACE_POINTS)
FError("tjunc fixups generated too many edges (max {})", MAX_SUPERFACE_POINTS);
@ -360,10 +313,7 @@ restart:
for (int32_t k = superface->w.size() - 1; k > j; k--)
VectorCopy(superface->w[k - 1], superface->w[k]);
vec3_t temp;
VectorMA(edge->origin, v->t, edge->dir, temp);
superface->w[j] = temp;
superface->w[j] = edge.first.origin + (edge.first.dir * *it);
goto restart;
}
}
@ -381,28 +331,12 @@ restart:
//============================================================================
static void tjunc_count_r(node_t *node)
{
face_t *f;
if (node->planenum == PLANENUM_LEAF)
return;
for (f = node->faces; f; f = f->next)
cWVerts += f->w.size();
tjunc_count_r(node->children[0]);
tjunc_count_r(node->children[1]);
}
static void tjunc_find_r(node_t *node)
{
face_t *f;
if (node->planenum == PLANENUM_LEAF)
return;
for (f = node->faces; f; f = f->next)
for (face_t *f = node->faces; f; f = f->next)
AddFaceEdges(f);
tjunc_find_r(node->children[0]);
@ -411,14 +345,12 @@ static void tjunc_find_r(node_t *node)
static void tjunc_fix_r(node_t *node, face_t *superface)
{
face_t *face, *next, *facelist;
if (node->planenum == PLANENUM_LEAF)
return;
facelist = NULL;
face_t *facelist = nullptr;
for (face = node->faces; face; face = next) {
for (face_t *face = node->faces, *next = nullptr; face; face = next) {
next = face->next;
FixFaceEdges(face, superface, &facelist);
}
@ -438,39 +370,13 @@ void TJunc(const mapentity_t *entity, node_t *headnode)
{
LogPrint(LOG_PROGRESS, "---- {} ----\n", __func__);
/*
* Guess edges = 1/2 verts
* Verts are arbitrarily multiplied by 2 because there appears to
* be a need for them to "grow" slightly.
*/
cWVerts = 0;
tjunc_count_r(headnode);
cWEdges = cWVerts;
cWVerts *= 2;
pWEdges.clear();
pWVerts = new wvert_t[cWVerts]{};
pWEdges = new wedge_t[cWEdges]{};
qvec3d maxs;
/*
* identify all points on common edges
* origin points won't allways be inside the map, so extend the hash area
*/
for (size_t i = 0; i < 3; i++) {
if (fabs(entity->bounds.maxs()[i]) > fabs(entity->bounds.mins()[i]))
maxs[i] = fabs(entity->bounds.maxs()[i]);
else
maxs[i] = fabs(entity->bounds.mins()[i]);
}
qvec3d mins = -maxs;
InitHash(mins, maxs);
numwedges = numwverts = 0;
numwverts = 0;
tjunc_find_r(headnode);
LogPrint(LOG_STAT, " {:8} world edges\n", numwedges);
LogPrint(LOG_STAT, " {:8} world edges\n", pWEdges.size());
LogPrint(LOG_STAT, " {:8} edge points\n", numwverts);
face_t superface;
@ -479,9 +385,6 @@ void TJunc(const mapentity_t *entity, node_t *headnode)
tjuncs = tjuncfaces = 0;
tjunc_fix_r(headnode, &superface);
delete[] pWVerts;
delete[] pWEdges;
LogPrint(LOG_STAT, " {:8} edges added by tjunctions\n", tjuncs);
LogPrint(LOG_STAT, " {:8} faces added by tjunctions\n", tjuncfaces);
}