surface faces now use list/vector

This commit is contained in:
Jonathan 2022-01-28 10:47:52 -05:00 committed by Eric Wasylishen
parent 10b592f64d
commit ed325eedea
13 changed files with 144 additions and 174 deletions

View File

@ -26,7 +26,7 @@
extern int csgmergefaces; extern int csgmergefaces;
// build surfaces is also used by GatherNodeFaces // build surfaces is also used by GatherNodeFaces
std::list<surface_t> BuildSurfaces(const std::map<int, face_t *> &planefaces); std::vector<surface_t> BuildSurfaces(std::map<int, std::list<face_t *>> &planefaces);
face_t *NewFaceFromFace(face_t *in); face_t *NewFaceFromFace(face_t *in);
void SplitFace(face_t *in, const qplane3d &split, face_t **front, face_t **back); void SplitFace(face_t *in, const qplane3d &split, face_t **front, face_t **back);
void UpdateFaceSphere(face_t *in); void UpdateFaceSphere(face_t *in);

View File

@ -221,10 +221,10 @@ constexpr int HULL_COLLISION = -1;
/* Create BSP brushes from map brushes */ /* Create BSP brushes from map brushes */
brush_stats_t Brush_LoadEntity(mapentity_t *entity, const int hullnum); brush_stats_t Brush_LoadEntity(mapentity_t *entity, const int hullnum);
std::list<surface_t> CSGFaces(const mapentity_t *entity); std::vector<surface_t> CSGFaces(const mapentity_t *entity);
void PortalizeWorld(const mapentity_t *entity, node_t *headnode, const int hullnum); void PortalizeWorld(const mapentity_t *entity, node_t *headnode, const int hullnum);
void TJunc(const mapentity_t *entity, node_t *headnode); void TJunc(const mapentity_t *entity, node_t *headnode);
node_t *SolidBSP(const mapentity_t *entity, std::list<surface_t> &surfhead, bool midsplit); node_t *SolidBSP(const mapentity_t *entity, std::vector<surface_t> &surfhead, bool midsplit);
int MakeFaceEdges(mapentity_t *entity, node_t *headnode); int MakeFaceEdges(mapentity_t *entity, node_t *headnode);
void ExportClipNodes(mapentity_t *entity, node_t *headnode, const int hullnum); void ExportClipNodes(mapentity_t *entity, node_t *headnode, const int hullnum);
void ExportDrawNodes(mapentity_t *entity, node_t *headnode, int firstface); void ExportDrawNodes(mapentity_t *entity, node_t *headnode, int firstface);
@ -238,7 +238,7 @@ void BSPX_Brushes_Init(struct bspxbrushes_s *ctx);
void ExportObj_Faces(const std::string &filesuffix, const std::vector<const face_t *> &faces); void ExportObj_Faces(const std::string &filesuffix, const std::vector<const face_t *> &faces);
void ExportObj_Brushes(const std::string &filesuffix, const std::vector<const brush_t *> &brushes); void ExportObj_Brushes(const std::string &filesuffix, const std::vector<const brush_t *> &brushes);
void ExportObj_Surfaces(const std::string &filesuffix, const std::list<surface_t> &surfaces); void ExportObj_Surfaces(const std::string &filesuffix, const std::vector<surface_t> &surfaces);
void ExportObj_Nodes(const std::string &filesuffix, const node_t *nodes); void ExportObj_Nodes(const std::string &filesuffix, const node_t *nodes);
void ExportObj_Marksurfaces(const std::string &filesuffix, const node_t *nodes); void ExportObj_Marksurfaces(const std::string &filesuffix, const node_t *nodes);

View File

@ -23,6 +23,5 @@
#include <list> #include <list>
face_t *MergeFaceToList(face_t *face, face_t *list); void MergeFaceToList(face_t *face, std::list<face_t *> &list);
face_t *FreeMergeListScraps(face_t *merged); void MergeAll(std::vector<surface_t> &surfhead);
void MergeAll(std::list<surface_t> &surfhead);

View File

@ -235,7 +235,7 @@ struct surface_t
bool onnode; // true if surface has already been used bool onnode; // true if surface has already been used
// as a splitting node // as a splitting node
bool detail_separator; // true if ALL faces are detail bool detail_separator; // true if ALL faces are detail
face_t *faces; // links to all faces on either side of the surf std::list<face_t *> faces; // links to all faces on either side of the surf
// bounds of all the face windings; calculated via calculateInfo // bounds of all the face windings; calculated via calculateInfo
aabb3d bounds; aabb3d bounds;
@ -246,6 +246,19 @@ struct surface_t
std::optional<size_t> outputplanenum; // only valid after WriteSurfacePlanes std::optional<size_t> outputplanenum; // only valid after WriteSurfacePlanes
inline surface_t shallowCopy()
{
surface_t copy;
copy.planenum = planenum;
copy.onnode = onnode;
copy.detail_separator = detail_separator;
copy.has_struct = has_struct;
copy.lmshift = lmshift;
return copy;
}
// calculate bounds & info // calculate bounds & info
inline void calculateInfo() inline void calculateInfo()
{ {
@ -253,10 +266,12 @@ struct surface_t
lmshift = std::numeric_limits<short>::max(); lmshift = std::numeric_limits<short>::max();
has_struct = false; has_struct = false;
for (const face_t *f = faces; f; f = f->next) { for (auto &f : faces) {
for (auto &contents : f->contents) for (auto &contents : f->contents) {
if (!contents.is_valid(options.target_game, false)) if (!contents.is_valid(options.target_game, false)) {
FError("Bad contents in face: {}", contents.to_string(options.target_game)); FError("Bad contents in face: {}", contents.to_string(options.target_game));
}
}
lmshift = min(f->lmshift.front, f->lmshift.back); lmshift = min(f->lmshift.front, f->lmshift.back);

View File

@ -26,4 +26,4 @@
extern std::atomic<int> splitnodes; extern std::atomic<int> splitnodes;
void DetailToSolid(node_t *node); void DetailToSolid(node_t *node);
void SubdivideFace(face_t *f, face_t **prevptr); std::list<face_t *>::iterator SubdivideFace(std::list<face_t *>::iterator it, std::list<face_t *> &surfaces);

View File

@ -23,5 +23,5 @@
#include <list> #include <list>
std::list<surface_t> GatherNodeFaces(node_t *headnode); std::vector<surface_t> GatherNodeFaces(node_t *headnode);
void FreeNodes(node_t* node); void FreeNodes(node_t* node);

View File

@ -332,7 +332,7 @@ static std::vector<face_t> CreateBrushFaces(const mapentity_t *src, hullbrush_t
} }
// this face is a keeper // this face is a keeper
face_t &f = facelist.emplace_front(); face_t &f = facelist.emplace_back();
f.planenum = PLANENUM_LEAF; f.planenum = PLANENUM_LEAF;
f.w.resize(w->size()); f.w.resize(w->size());

View File

@ -303,7 +303,7 @@ This plane map is later used to build up the surfaces for creating the BSP.
Not parallel. Not parallel.
================== ==================
*/ */
void SaveFacesToPlaneList(face_t *facelist, bool mirror, std::map<int, face_t *> &planefaces) static void SaveFacesToPlaneList(face_t *facelist, bool mirror, std::map<int, std::list<face_t *>> &planefaces)
{ {
face_t *face, *next; face_t *face, *next;
@ -317,8 +317,8 @@ void SaveFacesToPlaneList(face_t *facelist, bool mirror, std::map<int, face_t *>
continue; continue;
#endif #endif
face_t *plane_current_facelist = // returns empty (and inserts it) if plane is not in the map yet
planefaces[plane]; // returns `null` (and inserts it) if plane is not in the map yet std::list<face_t *> &plane_current_facelist = planefaces[plane];
if (mirror) { if (mirror) {
face_t *newface = NewFaceFromFace(face); face_t *newface = NewFaceFromFace(face);
@ -347,13 +347,9 @@ void SaveFacesToPlaneList(face_t *facelist, bool mirror, std::map<int, face_t *>
} }
} }
plane_current_facelist = MergeFaceToList(newface, plane_current_facelist); MergeFaceToList(newface, plane_current_facelist);
} }
plane_current_facelist = MergeFaceToList(face, plane_current_facelist); MergeFaceToList(face, plane_current_facelist);
plane_current_facelist = FreeMergeListScraps(plane_current_facelist);
// save the new list back in the map
planefaces[plane] = plane_current_facelist;
csgfaces++; csgfaces++;
} }
@ -456,9 +452,9 @@ visible face.
Not parallel. Not parallel.
================== ==================
*/ */
std::list<surface_t> BuildSurfaces(const std::map<int, face_t *> &planefaces) std::vector<surface_t> BuildSurfaces(std::map<int, std::list<face_t *>> &planefaces)
{ {
std::list<surface_t> surfaces; std::vector<surface_t> surfaces;
for (int i = 0; i < map.numplanes(); i++) { for (int i = 0; i < map.numplanes(); i++) {
const auto entry = planefaces.find(i); const auto entry = planefaces.find(i);
@ -466,14 +462,13 @@ std::list<surface_t> BuildSurfaces(const std::map<int, face_t *> &planefaces)
if (entry == planefaces.end()) if (entry == planefaces.end())
continue; continue;
Q_assert(entry->second != nullptr); Q_assert(!entry->second.empty());
/* create a new surface to hold the faces on this plane */ /* create a new surface to hold the faces on this plane */
surface_t &surf = surfaces.emplace_front(); surface_t &surf = surfaces.emplace_back();
surf.planenum = entry->first; surf.planenum = entry->first;
surf.faces = entry->second; surf.faces = std::move(entry->second);
for (const face_t *face = surf.faces; face; face = face->next) csgmergefaces += surf.faces.size();
csgmergefaces++;
/* Calculate bounding box and flags */ /* Calculate bounding box and flags */
surf.calculateInfo(); surf.calculateInfo();
@ -513,7 +508,7 @@ CSGFaces
Returns a list of surfaces containing all of the faces Returns a list of surfaces containing all of the faces
================== ==================
*/ */
std::list<surface_t> CSGFaces(const mapentity_t *entity) std::vector<surface_t> CSGFaces(const mapentity_t *entity)
{ {
LogPrint(LOG_PROGRESS, "---- {} ----\n", __func__); LogPrint(LOG_PROGRESS, "---- {} ----\n", __func__);
@ -634,7 +629,7 @@ std::list<surface_t> CSGFaces(const mapentity_t *entity)
}); });
// Non parallel part: // Non parallel part:
std::map<int, face_t *> planefaces; std::map<int, std::list<face_t *>> planefaces;
for (size_t i = 0; i < entity->brushes.size(); ++i) { for (size_t i = 0; i < entity->brushes.size(); ++i) {
const brush_t &brush = entity->brushes[i]; const brush_t &brush = entity->brushes[i];
face_t *outside = brushvec_outsides[i]; face_t *outside = brushvec_outsides[i];
@ -647,7 +642,7 @@ std::list<surface_t> CSGFaces(const mapentity_t *entity)
SaveFacesToPlaneList(outside, mirror, planefaces); SaveFacesToPlaneList(outside, mirror, planefaces);
} }
std::list<surface_t> surfaces = BuildSurfaces(planefaces); std::vector<surface_t> surfaces = BuildSurfaces(planefaces);
LogPrint(LOG_STAT, " {:8} brushfaces\n", brushfaces.load()); LogPrint(LOG_STAT, " {:8} brushfaces\n", brushfaces.load());
LogPrint(LOG_STAT, " {:8} csgfaces\n", csgfaces); LogPrint(LOG_STAT, " {:8} csgfaces\n", csgfaces);

View File

@ -128,14 +128,12 @@ void ExportObj_Brushes(const std::string &filesuffix, const std::vector<const br
ExportObj_Faces(filesuffix, faces); ExportObj_Faces(filesuffix, faces);
} }
void ExportObj_Surfaces(const std::string &filesuffix, const std::list<surface_t> &surfaces) void ExportObj_Surfaces(const std::string &filesuffix, const std::vector<surface_t> &surfaces)
{ {
std::vector<const face_t *> faces; std::vector<const face_t *> faces;
for (auto &surf : surfaces) { for (auto &surf : surfaces) {
for (const face_t *face = surf.faces; face; face = face->next) { std::copy(surf.faces.begin(), surf.faces.end(), std::back_inserter(faces));
faces.push_back(face);
}
} }
ExportObj_Faces(filesuffix, faces); ExportObj_Faces(filesuffix, faces);

View File

@ -157,51 +157,25 @@ static face_t *TryMerge(face_t *f1, face_t *f2)
MergeFaceToList MergeFaceToList
=============== ===============
*/ */
face_t *MergeFaceToList(face_t *face, face_t *list) void MergeFaceToList(face_t *face, std::list<face_t *> &list)
{ {
face_t *newf, *f; for (auto it = list.begin(); it != list.end(); ) {
f = list;
while (f) {
#ifdef PARANOID #ifdef PARANOID
CheckColinear(f); CheckColinear(f);
#endif #endif
newf = TryMerge(face, f); face_t *newf = TryMerge(face, *it);
if (newf) { if (newf) {
delete face; delete face;
f->w.clear(); // merged out, remove later list.erase(it);
face = newf; face = newf;
f = list; it = list.begin();
} else
f = f->next;
}
// didn't merge, so add at start
face->next = list;
return face;
}
/*
===============
FreeMergeListScraps
===============
*/
face_t *FreeMergeListScraps(face_t *merged)
{
face_t *head, *next;
head = NULL;
for (; merged; merged = next) {
next = merged->next;
if (!merged->w.size()) {
delete merged;
} else { } else {
merged->next = head; it++;
head = merged;
} }
} }
return head; list.emplace_back(face);
} }
/* /*
@ -211,16 +185,13 @@ MergePlaneFaces
*/ */
inline void MergePlaneFaces(surface_t &plane) inline void MergePlaneFaces(surface_t &plane)
{ {
face_t *merged = NULL, *next; std::list<face_t *> merged;
for (face_t *f = plane.faces; f; f = next) { for (auto &f : plane.faces) {
next = f->next; MergeFaceToList(f, merged);
merged = MergeFaceToList(f, merged);
} }
// Remove all empty faces (numpoints == -1) and add the remaining plane.faces = std::move(merged);
// faces to the plane
plane.faces = FreeMergeListScraps(merged);
} }
#include <tbb/parallel_for_each.h> #include <tbb/parallel_for_each.h>
@ -230,20 +201,16 @@ inline void MergePlaneFaces(surface_t &plane)
MergeAll MergeAll
============ ============
*/ */
void MergeAll(std::list<surface_t> &surfhead) void MergeAll(std::vector<surface_t> &surfhead)
{ {
std::atomic<int> mergefaces = 0, premergefaces = 0; std::atomic<int> mergefaces = 0, premergefaces = 0;
LogPrint(LOG_PROGRESS, "---- {} ----\n", __func__); LogPrint(LOG_PROGRESS, "---- {} ----\n", __func__);
tbb::parallel_for_each(surfhead, [&](surface_t &surf) { tbb::parallel_for_each(surfhead, [&](surface_t &surf) {
for (face_t *f = surf.faces; f; f = f->next) { premergefaces += surf.faces.size();
premergefaces++;
}
MergePlaneFaces(surf); MergePlaneFaces(surf);
for (face_t *f = surf.faces; f; f = f->next) { mergefaces += surf.faces.size();
mergefaces++;
}
}); });
LogPrint(LOG_STAT, " {:8} mergefaces (from {}; {:.0}% merged)\n", mergefaces, premergefaces, (static_cast<double>(mergefaces) / premergefaces) * 100.); LogPrint(LOG_STAT, " {:8} mergefaces (from {}; {:.0}% merged)\n", mergefaces, premergefaces, (static_cast<double>(mergefaces) / premergefaces) * 100.);

View File

@ -563,7 +563,7 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
* Take the brush_t's and clip off all overlapping and contained faces, * Take the brush_t's and clip off all overlapping and contained faces,
* leaving a perfect skin of the model with no hidden faces * leaving a perfect skin of the model with no hidden faces
*/ */
std::list<surface_t> surfs = CSGFaces(entity); std::vector<surface_t> surfs = CSGFaces(entity);
if (options.fObjExport && entity == pWorldEnt() && hullnum <= 0) { if (options.fObjExport && entity == pWorldEnt() && hullnum <= 0) {
ExportObj_Surfaces("post_csg", surfs); ExportObj_Surfaces("post_csg", surfs);

View File

@ -266,13 +266,13 @@ ChooseMidPlaneFromList
The clipping hull BSP doesn't worry about avoiding splits The clipping hull BSP doesn't worry about avoiding splits
================== ==================
*/ */
static std::list<surface_t>::iterator ChooseMidPlaneFromList(std::list<surface_t> &surfaces, const aabb3d &bounds) static std::vector<surface_t>::iterator ChooseMidPlaneFromList(std::vector<surface_t> &surfaces, const aabb3d &bounds)
{ {
/* pick the plane that splits the least */ /* pick the plane that splits the least */
vec_t bestaxialmetric = VECT_MAX; vec_t bestaxialmetric = VECT_MAX;
std::list<surface_t>::iterator bestaxialsurface = surfaces.end(); std::vector<surface_t>::iterator bestaxialsurface = surfaces.end();
vec_t bestanymetric = VECT_MAX; vec_t bestanymetric = VECT_MAX;
std::list<surface_t>::iterator bestanysurface = surfaces.end(); std::vector<surface_t>::iterator bestanysurface = surfaces.end();
for (int pass = 0; pass < 2; pass++) { for (int pass = 0; pass < 2; pass++) {
for (auto surf = surfaces.begin(); surf != surfaces.end(); surf++) { for (auto surf = surfaces.begin(); surf != surfaces.end(); surf++) {
@ -340,12 +340,12 @@ ChoosePlaneFromList
The real BSP heuristic The real BSP heuristic
================== ==================
*/ */
static std::list<surface_t>::iterator ChoosePlaneFromList(std::list<surface_t> &surfaces, const aabb3d &bounds) static std::vector<surface_t>::iterator ChoosePlaneFromList(std::vector<surface_t> &surfaces, const aabb3d &bounds)
{ {
/* pick the plane that splits the least */ /* pick the plane that splits the least */
int minsplits = INT_MAX - 1; int minsplits = INT_MAX - 1;
vec_t bestdistribution = VECT_MAX; vec_t bestdistribution = VECT_MAX;
std::list<surface_t>::iterator bestsurface = surfaces.end(); std::vector<surface_t>::iterator bestsurface = surfaces.end();
/* Two passes - exhaust all non-detail faces before details */ /* Two passes - exhaust all non-detail faces before details */
for (int pass = 0; pass < 2; pass++) { for (int pass = 0; pass < 2; pass++) {
@ -358,7 +358,7 @@ static std::list<surface_t>::iterator ChoosePlaneFromList(std::list<surface_t> &
* and check whether this is a hint split. * and check whether this is a hint split.
*/ */
bool hintsplit = false; bool hintsplit = false;
for (const face_t *face = surf->faces; face; face = face->next) { for (auto &face : surf->faces) {
if (map.mtexinfos.at(face->texinfo).flags.is_hint) if (map.mtexinfos.at(face->texinfo).flags.is_hint)
hintsplit = true; hintsplit = true;
} }
@ -377,7 +377,7 @@ static std::list<surface_t>::iterator ChoosePlaneFromList(std::list<surface_t> &
const qbsp_plane_t &plane2 = map.planes[surf2->planenum]; const qbsp_plane_t &plane2 = map.planes[surf2->planenum];
if (plane.type < 3 && plane.type == plane2.type) if (plane.type < 3 && plane.type == plane2.type)
continue; continue;
for (const face_t *face = surf2->faces; face; face = face->next) { for (auto &face : surf2->faces) {
const surfflags_t &flags = map.mtexinfos.at(face->texinfo).flags; const surfflags_t &flags = map.mtexinfos.at(face->texinfo).flags;
/* Don't penalize for splitting skip faces */ /* Don't penalize for splitting skip faces */
if (flags.is_skip) if (flags.is_skip)
@ -436,11 +436,11 @@ returns NULL if the surface list can not be divided any more (a leaf)
Called in parallel. Called in parallel.
================== ==================
*/ */
static std::list<surface_t>::iterator SelectPartition(std::list<surface_t> &surfaces) static std::vector<surface_t>::iterator SelectPartition(std::vector<surface_t> &surfaces)
{ {
// count onnode surfaces // count onnode surfaces
int surfcount = 0; int surfcount = 0;
std::list<surface_t>::iterator bestsurface = surfaces.end(); std::vector<surface_t>::iterator bestsurface = surfaces.end();
for (auto surf = surfaces.begin(); surf != surfaces.end(); surf++) { for (auto surf = surfaces.begin(); surf != surfaces.end(); surf++) {
if (!surf->onnode) { if (!surf->onnode) {
@ -505,88 +505,80 @@ static twosided<std::optional<surface_t>> DividePlane(surface_t &in, const qplan
if (qv::epsilonEqual(inplane->normal, split.normal, EQUAL_EPSILON)) { if (qv::epsilonEqual(inplane->normal, split.normal, EQUAL_EPSILON)) {
// check for exactly on node // check for exactly on node
if (inplane->dist == split.dist) { if (inplane->dist == split.dist) {
face_t *facet = in.faces;
in.faces = NULL;
in.onnode = true; in.onnode = true;
// divide the facets to the front and back sides // divide the facets to the front and back sides
surface_t newsurf(in); surface_t newsurf = in.shallowCopy();
// Prepend each face in facet list to either in or newsurf lists // Prepend each face in facet list to either in or newsurf lists
face_t *next; for (auto it = in.faces.begin(); it != in.faces.end(); ) {
for (; facet; facet = next) { if ((*it)->planeside == 1) {
next = facet->next; auto next = std::next(it);
if (facet->planeside == 1) { newsurf.faces.splice(newsurf.faces.begin(), in.faces, it);
facet->next = newsurf.faces; it = next;
newsurf.faces = facet;
} else { } else {
facet->next = in.faces; it++;
in.faces = facet;
} }
} }
// ericw -- added these CalcSurfaceInfo to recalculate the surf bbox. if (!in.faces.empty()) {
// pretty sure their omission here was a bug. in.calculateInfo();
newsurf.calculateInfo();
in.calculateInfo();
if (in.faces)
front = std::move(in); front = std::move(in);
}
if (newsurf.faces) if (!newsurf.faces.empty()) {
newsurf.calculateInfo();
back = std::move(newsurf); back = std::move(newsurf);
}
return { front, back }; return { front, back };
} }
if (inplane->dist > split.dist) if (inplane->dist > split.dist) {
front = std::move(in); front = std::move(in);
else } else {
back = std::move(in); back = std::move(in);
}
return { front, back }; return { front, back };
} }
// do a real split. may still end up entirely on one side // do a real split. may still end up entirely on one side
// OPTIMIZE: use bounding box for fast test // OPTIMIZE: use bounding box for fast test
face_t *frontlist = NULL; std::list<face_t *> frontlist, backlist;
face_t *backlist = NULL;
face_t *next; for (auto face : in.faces) {
for (face_t *facet = in.faces; facet; facet = next) { face_t *frontfrag = nullptr;
next = facet->next; face_t *backfrag = nullptr;
SplitFace(face, split, &frontfrag, &backfrag);
face_t *frontfrag = NULL;
face_t *backfrag = NULL;
SplitFace(facet, split, &frontfrag, &backfrag);
if (frontfrag) { if (frontfrag) {
frontfrag->next = frontlist; frontlist.emplace_back(frontfrag);
frontlist = frontfrag;
} }
if (backfrag) { if (backfrag) {
backfrag->next = backlist; backlist.emplace_back(backfrag);
backlist = backfrag;
} }
} }
// if nothing actually got split, just move the in plane // if nothing actually got split, just move the in plane
if (frontlist == NULL) { if (frontlist.empty()) {
in.faces = backlist; in.faces = std::move(backlist);
return { std::nullopt, std::move(in) }; return { std::nullopt, std::move(in) };
} }
if (backlist == NULL) { if (backlist.empty()) {
in.faces = frontlist; in.faces = std::move(frontlist);
return { std::move(in), std::nullopt }; return { std::move(in), std::nullopt };
} }
// stuff got split, so allocate one new plane and reuse in // stuff got split, so allocate one new plane and reuse in
surface_t newsurf(in); surface_t newsurf = in.shallowCopy();
newsurf.faces = backlist;
in.faces = frontlist;
// recalc bboxes and flags newsurf.faces = std::move(backlist);
newsurf.calculateInfo(); newsurf.calculateInfo();
in.faces = std::move(frontlist);
in.calculateInfo(); in.calculateInfo();
return { std::move(in), std::move(newsurf) }; return { std::move(in), std::move(newsurf) };
@ -612,7 +604,7 @@ original faces that have some fragment inside this leaf.
Called in parallel. Called in parallel.
================== ==================
*/ */
static void LinkConvexFaces(std::list<surface_t> &planelist, node_t *leafnode) static void LinkConvexFaces(std::vector<surface_t> &planelist, node_t *leafnode)
{ {
leafnode->faces = NULL; leafnode->faces = NULL;
leafnode->planenum = PLANENUM_LEAF; leafnode->planenum = PLANENUM_LEAF;
@ -621,11 +613,12 @@ static void LinkConvexFaces(std::list<surface_t> &planelist, node_t *leafnode)
std::optional<contentflags_t> contents; std::optional<contentflags_t> contents;
for (auto &surf : planelist) { for (auto &surf : planelist) {
for (face_t *f = surf.faces; f; f = f->next) { count += surf.faces.size();
count++;
for (auto &f : surf.faces) {
const int currentpri = contents.has_value() ? contents->priority(options.target_game) : -1; const int currentpri = contents.has_value() ? contents->priority(options.target_game) : -1;
const int fpri = f->contents[0].priority(options.target_game); const int fpri = f->contents[0].priority(options.target_game);
if (fpri > currentpri) { if (fpri > currentpri) {
contents = f->contents[0]; contents = f->contents[0];
} }
@ -675,11 +668,9 @@ static void LinkConvexFaces(std::list<surface_t> &planelist, node_t *leafnode)
leafnode->markfaces.reserve(count); leafnode->markfaces.reserve(count);
for (auto &surf : planelist) { for (auto &surf : planelist) {
for (face_t *f = surf.faces; f; ) { for (auto &f : surf.faces) {
face_t *next = f->next;
leafnode->markfaces.push_back(f->original); leafnode->markfaces.push_back(f->original);
delete f; delete f;
f = next;
} }
} }
} }
@ -699,20 +690,19 @@ Called in parallel.
*/ */
static face_t *LinkNodeFaces(surface_t &surface) static face_t *LinkNodeFaces(surface_t &surface)
{ {
face_t *list = NULL;
// subdivide large faces // subdivide large faces
face_t **prevptr = &surface.faces; for (auto it = surface.faces.begin(); it != surface.faces.end(); it++) {
face_t *f = *prevptr; it = SubdivideFace(it, surface.faces);
while (f) {
SubdivideFace(f, prevptr);
prevptr = &(*prevptr)->next;
f = *prevptr;
} }
surface.faces.reverse();
nodefaces += surface.faces.size();
face_t *list = NULL;
// copy // copy
for (face_t *f = surface.faces; f; f = f->next) { for (auto &f : surface.faces) {
nodefaces++;
face_t *newf = new face_t(*f); face_t *newf = new face_t(*f);
f->original = newf; f->original = newf;
newf->next = list; newf->next = list;
@ -729,9 +719,9 @@ PartitionSurfaces
Called in parallel. Called in parallel.
================== ==================
*/ */
static void PartitionSurfaces(std::list<surface_t> &surfaces, node_t *node) static void PartitionSurfaces(std::vector<surface_t> &surfaces, node_t *node)
{ {
std::list<surface_t>::iterator split = SelectPartition(surfaces); std::vector<surface_t>::iterator split = SelectPartition(surfaces);
if (split == surfaces.end()) { // this is a leaf node if (split == surfaces.end()) { // this is a leaf node
node->planenum = PLANENUM_LEAF; node->planenum = PLANENUM_LEAF;
@ -756,7 +746,7 @@ static void PartitionSurfaces(std::list<surface_t> &surfaces, node_t *node)
DivideNodeBounds(node, splitplane); DivideNodeBounds(node, splitplane);
// multiple surfaces, so split all the polysurfaces into front and back lists // multiple surfaces, so split all the polysurfaces into front and back lists
std::list<surface_t> frontlist, backlist; std::vector<surface_t> frontlist, backlist;
for (auto &surf : surfaces) { for (auto &surf : surfaces) {
auto frags = DividePlane(surf, splitplane); auto frags = DividePlane(surf, splitplane);
@ -769,14 +759,16 @@ static void PartitionSurfaces(std::list<surface_t> &surfaces, node_t *node)
} }
if (frags.front) { if (frags.front) {
if (!frags.front->faces) if (frags.front->faces.empty()) {
FError("Surface with no faces"); FError("Surface with no faces");
frontlist.emplace_front(std::move(*frags.front)); }
frontlist.emplace_back(std::move(*frags.front));
} }
if (frags.back) { if (frags.back) {
if (!frags.back->faces) if (frags.back->faces.empty()) {
FError("Surface with no faces"); FError("Surface with no faces");
backlist.emplace_front(std::move(*frags.back)); }
backlist.emplace_back(std::move(*frags.back));
} }
} }
@ -791,7 +783,7 @@ static void PartitionSurfaces(std::list<surface_t> &surfaces, node_t *node)
SolidBSP SolidBSP
================== ==================
*/ */
node_t *SolidBSP(const mapentity_t *entity, std::list<surface_t> &surfhead, bool midsplit) node_t *SolidBSP(const mapentity_t *entity, std::vector<surface_t> &surfhead, bool midsplit)
{ {
if (surfhead.empty()) { if (surfhead.empty()) {
/* /*

View File

@ -31,13 +31,13 @@ If the face is >256 in either texture direction, carve a valid sized
piece off and insert the remainder in the next link piece off and insert the remainder in the next link
=============== ===============
*/ */
void SubdivideFace(face_t *f, face_t **prevptr) std::list<face_t *>::iterator SubdivideFace(std::list<face_t *>::iterator it, std::list<face_t *> &surfaces)
{ {
vec_t mins, maxs; vec_t mins, maxs;
vec_t v; vec_t v;
int axis; int axis;
qbsp_plane_t plane; qbsp_plane_t plane;
face_t *front, *back, *next; face_t *front, *back;
const mtexinfo_t *tex; const mtexinfo_t *tex;
vec_t subdiv; vec_t subdiv;
vec_t extent; vec_t extent;
@ -45,15 +45,18 @@ void SubdivideFace(face_t *f, face_t **prevptr)
// subdivision disabled // subdivision disabled
if (!options.dxSubdivide) { if (!options.dxSubdivide) {
return; return it;
} }
face_t *f = *it;
/* special (non-surface cached) faces don't need subdivision */ /* special (non-surface cached) faces don't need subdivision */
tex = &map.mtexinfos.at(f->texinfo); tex = &map.mtexinfos.at(f->texinfo);
if (tex->flags.is_skip || tex->flags.is_hint || if (tex->flags.is_skip || tex->flags.is_hint ||
!options.target_game->surf_is_subdivided(tex->flags)) !options.target_game->surf_is_subdivided(tex->flags)) {
return; return it;
}
// subdivision is pretty much pointless other than because of lightmap block limits // subdivision is pretty much pointless other than because of lightmap block limits
// one lightmap block will always be added at the end, for smooth interpolation // one lightmap block will always be added at the end, for smooth interpolation
@ -91,8 +94,9 @@ void SubdivideFace(face_t *f, face_t **prevptr)
extent = ceil(maxs) - floor(mins); extent = ceil(maxs) - floor(mins);
// extent = maxs - mins; // extent = maxs - mins;
if (extent <= subdiv) if (extent <= subdiv) {
break; break;
}
// split it // split it
plane.normal = tmp; plane.normal = tmp;
@ -106,19 +110,20 @@ void SubdivideFace(face_t *f, face_t **prevptr)
// plane.dist = (mins + subdiv) / v; // plane.dist = (mins + subdiv) / v;
plane.dist = (mins + subdiv - 16) / v; plane.dist = (mins + subdiv - 16) / v;
next = f->next;
SplitFace(f, plane, &front, &back); SplitFace(f, plane, &front, &back);
if (!front || !back) { if (!front || !back) {
LogPrintLocked("didn't split\n"); LogPrintLocked("didn't split\n");
break; break;
// FError("Didn't split the polygon"); // FError("Didn't split the polygon");
} }
*prevptr = back; it = surfaces.erase(it);
back->next = front; it = surfaces.insert(it, front);
front->next = next; it = surfaces.insert(it, back);
f = back; f = back;
} }
} }
return it;
} }
static void FreeNode(node_t* node) static void FreeNode(node_t* node)
@ -152,7 +157,7 @@ have inside faces.
============================================================================= =============================================================================
*/ */
static void GatherNodeFaces_r(node_t *node, std::map<int, face_t *> &planefaces) static void GatherNodeFaces_r(node_t *node, std::map<int, std::list<face_t *>> &planefaces)
{ {
face_t *f, *next; face_t *f, *next;
@ -163,8 +168,7 @@ static void GatherNodeFaces_r(node_t *node, std::map<int, face_t *> &planefaces)
if (!f->w.size()) { // face was removed outside if (!f->w.size()) { // face was removed outside
delete f; delete f;
} else { } else {
f->next = planefaces[f->planenum]; planefaces[f->planenum].emplace_back(f);
planefaces[f->planenum] = f;
} }
} }
// don't attempt to free node->faces again as ownership has moved to the planefaces map // don't attempt to free node->faces again as ownership has moved to the planefaces map
@ -180,9 +184,9 @@ static void GatherNodeFaces_r(node_t *node, std::map<int, face_t *> &planefaces)
GatherNodeFaces GatherNodeFaces
================ ================
*/ */
std::list<surface_t> GatherNodeFaces(node_t *headnode) std::vector<surface_t> GatherNodeFaces(node_t *headnode)
{ {
std::map<int, face_t *> planefaces; std::map<int, std::list<face_t *>> planefaces;
GatherNodeFaces_r(headnode, planefaces); GatherNodeFaces_r(headnode, planefaces);
return BuildSurfaces(planefaces); return BuildSurfaces(planefaces);
} }