surface faces now use list/vector
This commit is contained in:
parent
10b592f64d
commit
ed325eedea
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
33
qbsp/csg4.cc
33
qbsp/csg4.cc
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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.);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
138
qbsp/solidbsp.cc
138
qbsp/solidbsp.cc
|
|
@ -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()) {
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue