diff --git a/include/qbsp/qbsp.hh b/include/qbsp/qbsp.hh index 33ae1288..7935e1b4 100644 --- a/include/qbsp/qbsp.hh +++ b/include/qbsp/qbsp.hh @@ -324,7 +324,7 @@ class mapentity_t; struct face_fragment_t { - std::vector output_vertices; // filled in by EmitVertices & TJunc + std::vector output_vertices, original_vertices; // filled in by EmitVertices & TJunc std::vector edges; // only filled in MakeFaceEdges std::optional outputnumber; // only valid for original faces after // write surfaces diff --git a/qbsp/faces.cc b/qbsp/faces.cc index 2b0102d6..523d9b72 100644 --- a/qbsp/faces.cc +++ b/qbsp/faces.cc @@ -82,6 +82,8 @@ static void EmitFaceVertices(face_t *f) for (size_t i = 0; i < f->w.size(); i++) { EmitVertex(f->w[i], f->output_vertices[i]); } + + f->original_vertices = f->output_vertices; } static void EmitVertices_R(node_t *node) @@ -136,7 +138,7 @@ inline int64_t GetEdge(const size_t &v1, const size_t &v2, const face_t *face) static void FindFaceFragmentEdges(face_t *face, face_fragment_t *fragment) { - fragment->outputnumber = std::nullopt; + Q_assert(fragment->outputnumber == std::nullopt); if (fragment->output_vertices.size() > MAXEDGES) { FError("Internal error: face->numpoints > MAXEDGES"); diff --git a/qbsp/tjunc.cc b/qbsp/tjunc.cc index 298c8a4a..d5230a28 100644 --- a/qbsp/tjunc.cc +++ b/qbsp/tjunc.cc @@ -125,7 +125,7 @@ static void FindEdgeVerts_FaceBounds_R(const node_t *node, const aabb3d &aabb, s } for (auto &face : node->facelist) { - for (auto &v : face->output_vertices) { + for (auto &v : face->original_vertices) { if (aabb.containsPoint(map.bsp.dvertexes[v])) { verts.push_back(v); } @@ -143,7 +143,7 @@ FindEdgeVerts_FaceBounds Use a loose AABB around the line and only capture vertices that intersect it. ========== */ -static void FindEdgeVerts_FaceBounds(const node_t *headnode, const node_t *node, const qvec3d &p1, const qvec3d &p2, std::vector &verts) +static void FindEdgeVerts_FaceBounds(const node_t *headnode, const qvec3d &p1, const qvec3d &p2, std::vector &verts) { // magic number, average of "usual" points per edge verts.reserve(8); @@ -162,7 +162,7 @@ max edge count. Modifies `superface`. Adds the results to the end of `output`. ================== */ -inline void SplitFaceIntoFragments(std::vector &superface, std::vector> &output) +inline void SplitFaceIntoFragments(std::vector &superface, std::list> &output) { size_t base = 0; size_t remaining = superface.size(); @@ -187,11 +187,11 @@ inline void SplitFaceIntoFragments(std::vector &superface, std::vector CreateSuperFace(node_t *headnode, node_t *node, face_t *f) +static std::vector CreateSuperFace(node_t *headnode, face_t *f) { std::vector superface; @@ -245,7 +245,7 @@ static std::vector CreateSuperFace(node_t *headnode, node_t *node, face_ qvec3d e2 = map.bsp.dvertexes[v2]; edge_verts.clear(); - FindEdgeVerts_FaceBounds(headnode, node, edge_start, e2, edge_verts); + FindEdgeVerts_FaceBounds(headnode, edge_start, e2, edge_verts); vec_t len; qvec3d edge_dir = qv::normalize(e2 - edge_start, len); @@ -265,9 +265,9 @@ It's still a convex face with wound vertices, though, so we can split it into several triangle fans. ================== */ -static std::vector> RetopologizeFace(const std::vector &vertices) +static std::list> RetopologizeFace(const std::vector &vertices) { - std::vector> result; + std::list> result; // the copy we're working on std::vector input(vertices); @@ -421,9 +421,9 @@ FixFaceEdges If the face has any T-junctions, fix them here. ================== */ -static void FixFaceEdges(node_t *headnode, node_t *node, face_t *f) +static void FixFaceEdges(node_t *headnode, face_t *f) { - std::vector superface = CreateSuperFace(headnode, node, f); + std::vector superface = CreateSuperFace(headnode, f); if (superface.size() < 3) { // entire face collapsed @@ -460,7 +460,7 @@ static void FixFaceEdges(node_t *headnode, node_t *node, face_t *f) } // temporary storage for result faces - std::vector> faces; + std::list> faces; if (i == superface.size()) { // can't simply rotate to eliminate zero-area triangles, so we have @@ -492,27 +492,28 @@ static void FixFaceEdges(node_t *headnode, node_t *node, face_t *f) Q_assert(faces.size()); // split giant superfaces into subfaces - size_t superface_count = faces.size(); - - for (size_t i = 0; i < superface_count; i++) { - SplitFaceIntoFragments(faces[i], faces); + for (auto &face : faces) { + SplitFaceIntoFragments(face, faces); } // move the results into the face - f->output_vertices = std::move(faces[0]); + f->output_vertices = std::move(faces.front()); f->fragments.resize(faces.size() - 1); - for (size_t i = 1; i < faces.size(); i++) { - f->fragments[i - 1].output_vertices = std::move(faces[i]); + i = 0; + for (auto it = ++faces.begin(); it != faces.end(); it++, i++) { + f->fragments[i].output_vertices = std::move(*it); } } +#include + /* ================== FixEdges_r ================== */ -static void FixEdges_r(node_t *headnode, node_t *node) +static void FindFaces_r(node_t *node, std::unordered_set &faces) { if (node->planenum == PLANENUM_LEAF) { return; @@ -521,12 +522,12 @@ static void FixEdges_r(node_t *headnode, node_t *node) for (auto &f : node->facelist) { // might have been omitted earlier, so `output_vertices` will be empty if (f->output_vertices.size()) { - FixFaceEdges(headnode, node, f.get()); + faces.insert(f.get()); } } - FixEdges_r(headnode, node->children[0].get()); - FixEdges_r(headnode, node->children[1].get()); + FindFaces_r(node->children[0].get(), faces); + FindFaces_r(node->children[1].get(), faces); } /* @@ -548,7 +549,13 @@ void TJunc(node_t *headnode) c_retopology = 0; c_faceretopology = 0; - FixEdges_r (headnode, headnode); + std::unordered_set faces; + + FindFaces_r(headnode, faces); + + logging::parallel_for_each(faces, [&](auto &face) { + FixFaceEdges(headnode, face); + }); logging::print (logging::flag::STAT, "{:5} edges degenerated\n", c_degenerate); logging::print (logging::flag::STAT, "{:5} faces degenerated\n", c_facecollapse); diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index cb8b4006..17a933ad 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -177,15 +177,16 @@ static void ExportLeaf(node_t *node) continue; // FIXME: this can happen when compiling some Q2 maps // as Q1. - if (!face->outputnumber.has_value()) - continue; - - /* emit a marksurface */ - map.bsp.dleaffaces.push_back(face->outputnumber.value()); + if (face->outputnumber.has_value()) { + /* emit a marksurface */ + map.bsp.dleaffaces.push_back(face->outputnumber.value()); + } /* grab tjunction split faces */ for (auto &fragment : face->fragments) { - map.bsp.dleaffaces.push_back(fragment.outputnumber.value()); + if (fragment.outputnumber.has_value()) { + map.bsp.dleaffaces.push_back(fragment.outputnumber.value()); + } } } dleaf.nummarksurfaces = static_cast(map.bsp.dleaffaces.size()) - dleaf.firstmarksurface;