From 055f865ef079500f3fdf67696acb9e53e25c36c0 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Sun, 13 Feb 2022 19:51:59 -0700 Subject: [PATCH] qbsp: add very rough pass of building visible faces - faces are subdivided where neeed - markfaces not calculated accurately - overlaps/clipping not handled --- include/qbsp/surfaces.hh | 1 + qbsp/qbsp.cc | 5 +++ qbsp/solidbsp.cc | 41 ------------------ qbsp/surfaces.cc | 94 ++++++++++++++++++++++++++++++++++++++++ testmaps/qbsp_simple.map | 4 +- 5 files changed, 102 insertions(+), 43 deletions(-) diff --git a/include/qbsp/surfaces.hh b/include/qbsp/surfaces.hh index 40af5f57..56ab0b0c 100644 --- a/include/qbsp/surfaces.hh +++ b/include/qbsp/surfaces.hh @@ -25,3 +25,4 @@ std::vector GatherNodeFaces(node_t *headnode); void FreeNodes(node_t* node); +void MakeVisibleFaces(mapentity_t *entity, node_t *headnode); \ No newline at end of file diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index a35c6b8d..86900ce3 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -605,11 +605,15 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum) else nodes = SolidBSP(entity, entity == pWorldEnt()); + MakeVisibleFaces(entity, nodes); + // build all the portals in the bsp tree // some portals are solid polygons, and some are paths to other leafs if (entity == pWorldEnt()) { // assume non-world bmodels are simple PortalizeWorld(entity, nodes, hullnum); + + #if 0 if (!options.fNofill && FillOutside(nodes, hullnum)) { FreeAllPortals(nodes); @@ -632,6 +636,7 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum) TJunc(entity, nodes); } } + #endif // Area portals if (options.target_game->id == GAME_QUAKE_II) { diff --git a/qbsp/solidbsp.cc b/qbsp/solidbsp.cc index 9d5bd6ba..ea674c9a 100644 --- a/qbsp/solidbsp.cc +++ b/qbsp/solidbsp.cc @@ -819,47 +819,6 @@ static void CreateLeaf(const std::vector &brushes, node_t *leafnode) #endif } -// fixme-brushbsp: move SubdivideFace call somewhere else -#if 0 -/* -================== -LinkNodeFaces - -First subdivides surface->faces. -Then, duplicates the list of subdivided faces and returns it. - -For each surface->faces, ->original is set to the respective duplicate that -is returned here (why?). - -Called in parallel. -================== -*/ -static std::list LinkNodeFaces(surface_t &surface) -{ - // subdivide large faces - for (auto it = surface.faces.begin(); it != surface.faces.end(); it++) { - it = SubdivideFace(it, surface.faces); - } - - surface.faces.reverse(); - - nodefaces += surface.faces.size(); - - std::list list; - - // copy - for (auto &f : surface.faces) { - face_t *newf = new face_t(*f); - Q_assert(newf->original == nullptr); - - list.push_front(newf); - f->original = newf; - } - - return list; -} -#endif - /* ================== PartitionBrushes diff --git a/qbsp/surfaces.cc b/qbsp/surfaces.cc index 38a88957..9a295cd0 100644 --- a/qbsp/surfaces.cc +++ b/qbsp/surfaces.cc @@ -511,3 +511,97 @@ int MakeFaceEdges(mapentity_t *entity, node_t *headnode) return firstface; } + +//=========================================================================== + +static int c_nodefaces; + +static void AddMarksurfaces_r(face_t *face, node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) { + node->markfaces.push_back(face); + return; + } + + AddMarksurfaces_r(face, node->children[0]); + AddMarksurfaces_r(face, node->children[1]); +} + +void AddFaceToTree_r(face_t *face, node_t* node) +{ + if (node->planenum == PLANENUM_LEAF) { + if (!face->w.size()) { + // spurious + return; + } + FError("couldn't find node for face"); + } + + if (face->planenum == node->planenum) { + // found the correct plane - add the face to it. + + ++c_nodefaces; + + // subdivide large faces + // fixme-brushbsp: weird calling convention + auto parts = std::list{face}; + for (auto it = parts.begin(); it != parts.end(); it++) { + it = SubdivideFace(it, parts); + } + + for (face_t *part : parts) { + node->facelist.push_back(part); + + // Now that the final face has been added + // fixme-brushbsp: do this as a postprocessing step + AddMarksurfaces_r(part, node); + } + + return; + } + + // fixme-brushbsp: we need to handle the case of the face being near enough that it gets clipped away, + // but not face->planenum == node->planenum + auto [frontWinding, backWinding] = face->w.clip(map.planes[node->planenum]); + if (frontWinding) { + auto *newFace = new face_t{*face}; + newFace->w = *frontWinding; + AddFaceToTree_r(newFace, node->children[0]); + } + if (backWinding) { + auto *newFace = new face_t{*face}; + newFace->w = *backWinding; + AddFaceToTree_r(newFace, node->children[1]); + } + + delete face; +} + +/* +================ +MakeVisibleFaces + +Given a completed BSP tree and a list of brushes (in `entity`), + +- filters the brush faces into the BSP, finding the correct nodes they end up on +- clips the faces by other brushes. + + first iteration, we can just do an exhaustive check against all brushes +================ +*/ +void MakeVisibleFaces(mapentity_t* entity, node_t* headnode) +{ + c_nodefaces = 0; + + for (auto &brush : entity->brushes) { + for (auto &face : brush.faces) { + + face_t *temp = NewFaceFromFace(&face); + temp->w = face.w; + + AddFaceToTree_r(temp, headnode); + } + } + + LogPrint("{} nodefaces\n", c_nodefaces); +} diff --git a/testmaps/qbsp_simple.map b/testmaps/qbsp_simple.map index 9db90239..c23abca2 100644 --- a/testmaps/qbsp_simple.map +++ b/testmaps/qbsp_simple.map @@ -13,8 +13,8 @@ ( -80 -96 80 ) ( -81 -96 80 ) ( -80 -96 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 1 1 ( -80 -432 80 ) ( -80 -431 80 ) ( -81 -432 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 1 1 ( -160 -112 96 ) ( -161 -112 96 ) ( -160 -111 96 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 1 1 -( -160 -32 96 ) ( -160 -32 97 ) ( -161 -32 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 1 1 -( -64 -432 80 ) ( -64 -432 81 ) ( -64 -431 80 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 1 1 +( -160 128 96 ) ( -160 128 97 ) ( -161 128 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 1 1 +( 144 -432 80 ) ( 144 -432 81 ) ( 144 -431 80 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 1 1 } // brush 1 {