Merge branch 'brushbsp' of https://github.com/ericwa/ericw-tools into brushbsp
This commit is contained in:
commit
3527dcf39b
|
|
@ -514,6 +514,17 @@ std::vector<qvec3f> GLM_FacePoints(const mbsp_t *bsp, const mface_t *face)
|
|||
return points;
|
||||
}
|
||||
|
||||
polylib::winding_t Face_Winding(const mbsp_t *bsp, const mface_t *face)
|
||||
{
|
||||
polylib::winding_t w{};
|
||||
|
||||
for (int j = 0; j < face->numedges; j++) {
|
||||
w.push_back(Face_PointAtIndex(bsp, face, j));
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
qvec3f Face_Centroid(const mbsp_t *bsp, const mface_t *face)
|
||||
{
|
||||
auto points = GLM_FacePoints(bsp, face);
|
||||
|
|
|
|||
|
|
@ -157,9 +157,12 @@ struct surfflags_t
|
|||
// native flags value; what's written to the BSP basically
|
||||
int32_t native;
|
||||
|
||||
// an invisible surface
|
||||
// an invisible surface (Q1 "skip" texture, Q2 SURF_NODRAW)
|
||||
bool is_skip;
|
||||
|
||||
// completely ignore, allowing non-closed brushes (Q2 SURF_SKIP)
|
||||
bool is_hintskip;
|
||||
|
||||
// hint surface
|
||||
bool is_hint;
|
||||
|
||||
|
|
@ -205,7 +208,7 @@ struct surfflags_t
|
|||
private:
|
||||
constexpr auto as_tuple() const
|
||||
{
|
||||
return std::tie(native, is_skip, is_hint, no_dirt, no_shadow, no_bounce, no_minlight, no_expand, light_ignore,
|
||||
return std::tie(native, is_skip, is_hintskip, is_hint, no_dirt, no_shadow, no_bounce, no_minlight, no_expand, light_ignore,
|
||||
phong_angle, phong_angle_concave, minlight, minlight_color, light_alpha);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <common/bspfile.hh>
|
||||
#include <common/mathlib.hh>
|
||||
#include <common/qvec.hh>
|
||||
#include <common/polylib.hh>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -78,6 +79,7 @@ const qvec3f &Face_PointAtIndex(const mbsp_t *bsp, const mface_t *f);
|
|||
const qvec3f &Vertex_GetPos(const mbsp_t *bsp, int num);
|
||||
qvec3d Face_Normal(const mbsp_t *bsp, const mface_t *f);
|
||||
std::vector<qvec3f> GLM_FacePoints(const mbsp_t *bsp, const mface_t *face);
|
||||
polylib::winding_t Face_Winding(const mbsp_t *bsp, const mface_t *face);
|
||||
qvec3f Face_Centroid(const mbsp_t *bsp, const mface_t *face);
|
||||
void Face_DebugPrint(const mbsp_t *bsp, const mface_t *face);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <optional>
|
||||
|
||||
class mapentity_t;
|
||||
struct maptexinfo_t;
|
||||
|
||||
struct side_t
|
||||
{
|
||||
|
|
@ -42,16 +43,25 @@ struct side_t
|
|||
// non-visible means we can discard the brush side
|
||||
// (avoiding generating a BSP spit, so expanding it outwards)
|
||||
bool bevel; // don't ever use for bsp splitting
|
||||
|
||||
bool tested;
|
||||
|
||||
const maptexinfo_t& get_texinfo() const;
|
||||
};
|
||||
|
||||
class mapbrush_t;
|
||||
|
||||
struct bspbrush_t {
|
||||
/**
|
||||
* The brushes in the mapentity_t::brushes vector are considered originals. Brush fragments created during
|
||||
* the BrushBSP will have this pointing back to the original brush in mapentity_t::brushes.
|
||||
*
|
||||
* fixme-brushbsp: this is supposed to be a mapbrush_t
|
||||
*/
|
||||
bspbrush_t *original;
|
||||
uint32_t file_order;
|
||||
aabb3d bounds;
|
||||
int side, testside; // side of node during construction
|
||||
std::vector<side_t> sides;
|
||||
contentflags_t contents; /* BSP contents */
|
||||
short lmshift; /* lightmap scaling (qu/lightmap pixel), passed to the light util */
|
||||
|
|
@ -59,9 +69,9 @@ struct bspbrush_t {
|
|||
mapentity_t *func_areaportal;
|
||||
|
||||
void update_bounds();
|
||||
};
|
||||
|
||||
class mapbrush_t;
|
||||
std::unique_ptr<bspbrush_t> copy_unique() const;
|
||||
};
|
||||
|
||||
qplane3d Face_Plane(const face_t *face);
|
||||
qplane3d Face_Plane(const side_t *face);
|
||||
|
|
|
|||
|
|
@ -29,16 +29,15 @@
|
|||
#include <optional>
|
||||
#include <memory>
|
||||
|
||||
extern std::atomic<int> splitnodes;
|
||||
|
||||
struct bspbrush_t;
|
||||
struct node_t;
|
||||
struct face_t;
|
||||
class mapentity_t;
|
||||
struct tree_t;
|
||||
|
||||
void DetailToSolid(node_t *node);
|
||||
void PruneNodes(node_t *node);
|
||||
bool WindingIsTiny(const winding_t &w, double size = 0.2);
|
||||
twosided<std::unique_ptr<bspbrush_t>> SplitBrush(std::unique_ptr<bspbrush_t> brush, const qplane3d &split);
|
||||
std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds);
|
||||
tree_t *BrushBSP(std::vector<std::unique_ptr<bspbrush_t>> brushlist);
|
||||
|
||||
// compatibility version
|
||||
tree_t *BrushBSP(mapentity_t *entity, bool midsplit);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <utility>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
struct bspbrush_t;
|
||||
|
||||
|
|
@ -124,6 +125,8 @@ struct maptexdata_t
|
|||
|
||||
#include <common/imglib.hh>
|
||||
|
||||
extern std::recursive_mutex map_planes_lock;
|
||||
|
||||
struct mapdata_t
|
||||
{
|
||||
/* Arrays of actual items */
|
||||
|
|
@ -168,6 +171,11 @@ struct mapdata_t
|
|||
|
||||
const std::string &texinfoTextureName(int texinfo) const { return miptexTextureName(mtexinfos.at(texinfo).miptex); }
|
||||
|
||||
inline qbsp_plane_t get_plane(int pnum) {
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
return planes.at(pnum);
|
||||
}
|
||||
|
||||
int skip_texinfo;
|
||||
|
||||
mapentity_t *world_entity();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <qbsp/qbsp.hh>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
struct side_t;
|
||||
|
||||
|
|
@ -43,7 +44,7 @@ struct portal_t
|
|||
|
||||
struct tree_t
|
||||
{
|
||||
node_t *headnode;
|
||||
std::unique_ptr<node_t> headnode;
|
||||
node_t outside_node = {}; // portals outside the world face this
|
||||
aabb3d bounds;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
|
@ -209,6 +210,8 @@ public:
|
|||
this, "oldrottex", false, &debugging_group, "use old rotate_ brush texturing aligned at (0 0 0)"};
|
||||
setting_scalar epsilon{
|
||||
this, "epsilon", 0.0001, 0.0, 1.0, &debugging_group, "customize epsilon value for point-on-plane checks"};
|
||||
setting_scalar microvolume{
|
||||
this, "microvolume", 1.0, 0.0, 1000.0, &debugging_group, "microbrush volume"};
|
||||
setting_bool contenthack{this, "contenthack", false, &debugging_group,
|
||||
"hack to fix leaks through solids. causes missing faces in some cases so disabled by default"};
|
||||
setting_bool leaktest{this, "leaktest", false, &map_development_group, "make compilation fail if the map leaks"};
|
||||
|
|
@ -349,18 +352,23 @@ struct face_t : face_fragment_t
|
|||
// there is a node_t structure for every node and leaf in the bsp tree
|
||||
|
||||
struct bspbrush_t;
|
||||
struct side_t;
|
||||
|
||||
struct node_t
|
||||
{
|
||||
// both leafs and nodes
|
||||
aabb3d bounds; // bounding volume, not just points inside
|
||||
node_t *parent;
|
||||
// this is also a bounding volume like `bounds`
|
||||
std::unique_ptr<bspbrush_t> volume; // one for each leaf/node
|
||||
|
||||
// information for decision nodes
|
||||
int planenum; // -1 = leaf node
|
||||
int firstface; // decision node only
|
||||
int numfaces; // decision node only
|
||||
node_t *children[2]; // children[0] = front side, children[1] = back side of plane. only valid for decision nodes
|
||||
twosided<std::unique_ptr<node_t>> children; // children[0] = front side, children[1] = back side of plane. only valid for decision nodes
|
||||
std::list<face_t *> facelist; // decision nodes only, list for both sides
|
||||
side_t *side; // the side that created the node
|
||||
|
||||
// information for leafs
|
||||
contentflags_t contents; // leaf nodes (0 for decision nodes)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,18 @@
|
|||
#include <qbsp/map.hh>
|
||||
#include <qbsp/qbsp.hh>
|
||||
|
||||
const maptexinfo_t& side_t::get_texinfo() const
|
||||
{
|
||||
return map.mtexinfos[this->texinfo];
|
||||
}
|
||||
|
||||
std::unique_ptr<bspbrush_t> bspbrush_t::copy_unique() const
|
||||
{
|
||||
bspbrush_t *copy = new bspbrush_t{*this};
|
||||
|
||||
return std::unique_ptr<bspbrush_t>(copy);
|
||||
}
|
||||
|
||||
/*
|
||||
* Beveled clipping hull can generate many extra faces
|
||||
*/
|
||||
|
|
@ -56,6 +68,7 @@ Face_Plane
|
|||
*/
|
||||
qplane3d Face_Plane(const face_t *face)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
const qplane3d &result = map.planes.at(face->planenum);
|
||||
|
||||
if (face->planeside) {
|
||||
|
|
@ -67,6 +80,7 @@ qplane3d Face_Plane(const face_t *face)
|
|||
|
||||
qplane3d Face_Plane(const side_t *face)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
const qplane3d &result = map.planes.at(face->planenum);
|
||||
|
||||
if (face->planeside) {
|
||||
|
|
@ -85,6 +99,7 @@ Note: this will not catch 0 area polygons
|
|||
*/
|
||||
static void CheckFace(side_t *face, const mapface_t &sourceface)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
const qbsp_plane_t &plane = map.planes.at(face->planenum);
|
||||
|
||||
if (face->w.size() < 3) {
|
||||
|
|
@ -209,6 +224,8 @@ inline int plane_hash_fn(const qplane3d &p)
|
|||
|
||||
static void PlaneHash_Add(const qplane3d &p, int index)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
const int hash = plane_hash_fn(p);
|
||||
map.planehash[hash].push_back(index);
|
||||
}
|
||||
|
|
@ -219,6 +236,8 @@ static void PlaneHash_Add(const qplane3d &p, int index)
|
|||
*/
|
||||
static int NewPlane(const qplane3d &plane, planeside_t *side)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
vec_t len = qv::length(plane.normal);
|
||||
|
||||
if (len < 1 - options.epsilon.value() || len > 1 + options.epsilon.value())
|
||||
|
|
@ -248,6 +267,8 @@ static int NewPlane(const qplane3d &plane, planeside_t *side)
|
|||
*/
|
||||
int FindPlane(const qplane3d &plane, planeside_t *side)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
for (int i : map.planehash[plane_hash_fn(plane)]) {
|
||||
const qbsp_plane_t &p = map.planes.at(i);
|
||||
if (qv::epsilonEqual(p, plane)) {
|
||||
|
|
@ -269,6 +290,8 @@ int FindPlane(const qplane3d &plane, planeside_t *side)
|
|||
*/
|
||||
int FindPositivePlane(int planenum)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
const auto &plane = map.planes[planenum];
|
||||
|
||||
// already positive, or it's PLANE_ANY_x which doesn't matter
|
||||
|
|
|
|||
1192
qbsp/brushbsp.cc
1192
qbsp/brushbsp.cc
File diff suppressed because it is too large
Load Diff
|
|
@ -135,8 +135,8 @@ static void ExportObj_Nodes_r(const node_t *node, std::vector<const face_t *> *d
|
|||
dest->push_back(face);
|
||||
}
|
||||
|
||||
ExportObj_Nodes_r(node->children[0], dest);
|
||||
ExportObj_Nodes_r(node->children[1], dest);
|
||||
ExportObj_Nodes_r(node->children[0].get(), dest);
|
||||
ExportObj_Nodes_r(node->children[1].get(), dest);
|
||||
}
|
||||
|
||||
void ExportObj_Nodes(const std::string &filesuffix, const node_t *nodes)
|
||||
|
|
@ -149,8 +149,8 @@ void ExportObj_Nodes(const std::string &filesuffix, const node_t *nodes)
|
|||
static void ExportObj_Marksurfaces_r(const node_t *node, std::unordered_set<const face_t *> *dest)
|
||||
{
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
ExportObj_Marksurfaces_r(node->children[0], dest);
|
||||
ExportObj_Marksurfaces_r(node->children[1], dest);
|
||||
ExportObj_Marksurfaces_r(node->children[0].get(), dest);
|
||||
ExportObj_Marksurfaces_r(node->children[1].get(), dest);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -185,8 +185,8 @@ static void FreeNode(node_t *node)
|
|||
void FreeNodes(node_t *node)
|
||||
{
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
FreeNodes(node->children[0]);
|
||||
FreeNodes(node->children[1]);
|
||||
FreeNodes(node->children[0].get());
|
||||
FreeNodes(node->children[1].get());
|
||||
}
|
||||
FreeNode(node);
|
||||
}
|
||||
|
|
@ -369,9 +369,8 @@ static int MakeFaceEdges_r(mapentity_t *entity, node_t *node, int progress)
|
|||
FindFaceEdges(entity, f);
|
||||
}
|
||||
|
||||
logging::percent(progress, splitnodes, entity);
|
||||
progress = MakeFaceEdges_r(entity, node->children[0], progress);
|
||||
progress = MakeFaceEdges_r(entity, node->children[1], progress);
|
||||
progress = MakeFaceEdges_r(entity, node->children[0].get(), progress);
|
||||
progress = MakeFaceEdges_r(entity, node->children[1].get(), progress);
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
|
@ -449,8 +448,8 @@ static void GrowNodeRegion(mapentity_t *entity, node_t *node)
|
|||
|
||||
node->numfaces = static_cast<int>(map.bsp.dfaces.size()) - node->firstface;
|
||||
|
||||
GrowNodeRegion(entity, node->children[0]);
|
||||
GrowNodeRegion(entity, node->children[1]);
|
||||
GrowNodeRegion(entity, node->children[0].get());
|
||||
GrowNodeRegion(entity, node->children[1].get());
|
||||
}
|
||||
|
||||
static void CountFace(mapentity_t *entity, face_t *f, size_t &facesCount, size_t &vertexesCount)
|
||||
|
|
@ -479,8 +478,8 @@ static void CountData_r(mapentity_t *entity, node_t *node, size_t &facesCount, s
|
|||
CountFace(entity, f, facesCount, vertexesCount);
|
||||
}
|
||||
|
||||
CountData_r(entity, node->children[0], facesCount, vertexesCount);
|
||||
CountData_r(entity, node->children[1], facesCount, vertexesCount);
|
||||
CountData_r(entity, node->children[0].get(), facesCount, vertexesCount);
|
||||
CountData_r(entity, node->children[1].get(), facesCount, vertexesCount);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -505,7 +504,6 @@ int MakeFaceEdges(mapentity_t *entity, node_t *headnode)
|
|||
|
||||
firstface = static_cast<int>(map.bsp.dfaces.size());
|
||||
MakeFaceEdges_r(entity, headnode, 0);
|
||||
logging::percent(splitnodes, splitnodes, entity == map.world_entity());
|
||||
|
||||
pEdgeFaces0.clear();
|
||||
pEdgeFaces1.clear();
|
||||
|
|
@ -536,14 +534,15 @@ static void AddMarksurfaces_r(face_t *face, face_t *face_copy, node_t *node)
|
|||
return;
|
||||
}
|
||||
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
const qbsp_plane_t &splitplane = map.planes.at(node->planenum);
|
||||
|
||||
auto [frontFragment, backFragment] = SplitFace(face_copy, splitplane);
|
||||
if (frontFragment) {
|
||||
AddMarksurfaces_r(face, frontFragment, node->children[0]);
|
||||
AddMarksurfaces_r(face, frontFragment, node->children[0].get());
|
||||
}
|
||||
if (backFragment) {
|
||||
AddMarksurfaces_r(face, backFragment, node->children[1]);
|
||||
AddMarksurfaces_r(face, backFragment, node->children[1].get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -568,15 +567,15 @@ void MakeMarkFaces(mapentity_t* entity, node_t* node)
|
|||
face_t *face_copy = CopyFace(face);
|
||||
|
||||
if (face->planeside == 0) {
|
||||
AddMarksurfaces_r(face, face_copy, node->children[0]);
|
||||
AddMarksurfaces_r(face, face_copy, node->children[0].get());
|
||||
} else {
|
||||
AddMarksurfaces_r(face, face_copy, node->children[1]);
|
||||
AddMarksurfaces_r(face, face_copy, node->children[1].get());
|
||||
}
|
||||
}
|
||||
|
||||
// process child nodes recursively
|
||||
MakeMarkFaces(entity, node->children[0]);
|
||||
MakeMarkFaces(entity, node->children[1]);
|
||||
MakeMarkFaces(entity, node->children[0].get());
|
||||
MakeMarkFaces(entity, node->children[1].get());
|
||||
}
|
||||
|
||||
struct makefaces_stats_t {
|
||||
|
|
@ -663,8 +662,8 @@ static void MakeFaces_r(node_t *node, makefaces_stats_t& stats)
|
|||
// recurse down to leafs
|
||||
if (node->planenum != PLANENUM_LEAF)
|
||||
{
|
||||
MakeFaces_r(node->children[0], stats);
|
||||
MakeFaces_r(node->children[1], stats);
|
||||
MakeFaces_r(node->children[0].get(), stats);
|
||||
MakeFaces_r(node->children[1].get(), stats);
|
||||
|
||||
// merge together all visible faces on the node
|
||||
if (!options.nomerge.value())
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include <common/qvec.hh>
|
||||
|
||||
mapdata_t map;
|
||||
std::recursive_mutex map_planes_lock;
|
||||
|
||||
const std::optional<img::texture_meta> &mapdata_t::load_image_meta(const std::string_view &name)
|
||||
{
|
||||
|
|
@ -2372,6 +2373,8 @@ from q3map
|
|||
*/
|
||||
void WriteBspBrushMap(const fs::path &name, const std::vector<std::unique_ptr<bspbrush_t>> &list)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
logging::print("writing {}\n", name);
|
||||
std::ofstream f(name);
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ static face_t *TryMerge(face_t *f1, face_t *f2)
|
|||
|
||||
// check slope of connected lines
|
||||
// if the slopes are colinear, the point can be removed
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
const auto &plane = map.planes.at(f1->planenum);
|
||||
planenormal = plane.normal;
|
||||
if (f1->planeside)
|
||||
|
|
@ -211,8 +212,8 @@ static void CollectNodes_R(node_t *node, std::vector<node_t *> &allnodes)
|
|||
return;
|
||||
}
|
||||
|
||||
CollectNodes_R(node->children[0], allnodes);
|
||||
CollectNodes_R(node->children[1], allnodes);
|
||||
CollectNodes_R(node->children[0].get(), allnodes);
|
||||
CollectNodes_R(node->children[1].get(), allnodes);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -58,20 +58,21 @@ static node_t *PointInLeaf(node_t *node, const qvec3d &point)
|
|||
return node;
|
||||
}
|
||||
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
const auto &plane = map.planes.at(node->planenum);
|
||||
vec_t dist = plane.distance_to(point);
|
||||
|
||||
if (dist > 0) {
|
||||
// point is on the front of the node plane
|
||||
return PointInLeaf(node->children[0], point);
|
||||
return PointInLeaf(node->children[0].get(), point);
|
||||
} else if (dist < 0) {
|
||||
// point is on the back of the node plane
|
||||
return PointInLeaf(node->children[1], point);
|
||||
return PointInLeaf(node->children[1].get(), point);
|
||||
} else {
|
||||
// point is exactly on the node plane
|
||||
|
||||
node_t *front = PointInLeaf(node->children[0], point);
|
||||
node_t *back = PointInLeaf(node->children[1], point);
|
||||
node_t *front = PointInLeaf(node->children[0].get(), point);
|
||||
node_t *back = PointInLeaf(node->children[1].get(), point);
|
||||
|
||||
// prefer the opaque one
|
||||
if (LeafSealsMap(front)) {
|
||||
|
|
@ -89,8 +90,8 @@ static void ClearOccupied_r(node_t *node)
|
|||
node->occupant = nullptr;
|
||||
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
ClearOccupied_r(node->children[0]);
|
||||
ClearOccupied_r(node->children[1]);
|
||||
ClearOccupied_r(node->children[0].get());
|
||||
ClearOccupied_r(node->children[1].get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,8 +118,8 @@ static void MarkClusterOutsideDistance_R(node_t* node, int outside_distance)
|
|||
node->outside_distance = outside_distance;
|
||||
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
MarkClusterOutsideDistance_R(node->children[0], outside_distance);
|
||||
MarkClusterOutsideDistance_R(node->children[1], outside_distance);
|
||||
MarkClusterOutsideDistance_R(node->children[0].get(), outside_distance);
|
||||
MarkClusterOutsideDistance_R(node->children[1].get(), outside_distance);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -328,8 +329,8 @@ static void FindOccupiedClusters_R(node_t *node, std::vector<node_t *>& result)
|
|||
}
|
||||
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
FindOccupiedClusters_R(node->children[0], result);
|
||||
FindOccupiedClusters_R(node->children[1], result);
|
||||
FindOccupiedClusters_R(node->children[0].get(), result);
|
||||
FindOccupiedClusters_R(node->children[1].get(), result);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -362,8 +363,8 @@ static void MarkAllBrushSidesVisible_R(node_t *node)
|
|||
{
|
||||
// descend to leafs
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
MarkAllBrushSidesVisible_R(node->children[0]);
|
||||
MarkAllBrushSidesVisible_R(node->children[1]);
|
||||
MarkAllBrushSidesVisible_R(node->children[0].get());
|
||||
MarkAllBrushSidesVisible_R(node->children[1].get());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -385,8 +386,8 @@ static void MarkVisibleBrushSides_R(node_t *node)
|
|||
{
|
||||
// descent to leafs
|
||||
if (!(node->planenum == PLANENUM_LEAF)) {
|
||||
MarkVisibleBrushSides_R(node->children[0]);
|
||||
MarkVisibleBrushSides_R(node->children[1]);
|
||||
MarkVisibleBrushSides_R(node->children[0].get());
|
||||
MarkVisibleBrushSides_R(node->children[1].get());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -429,8 +430,8 @@ static void MarkVisibleBrushSides_R(node_t *node)
|
|||
static void OutLeafsToSolid_r(node_t *node, int *outleafs_count, settings::filltype_t filltype)
|
||||
{
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
OutLeafsToSolid_r(node->children[0], outleafs_count, filltype);
|
||||
OutLeafsToSolid_r(node->children[1], outleafs_count, filltype);
|
||||
OutLeafsToSolid_r(node->children[0].get(), outleafs_count, filltype);
|
||||
OutLeafsToSolid_r(node->children[1].get(), outleafs_count, filltype);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -467,8 +468,8 @@ static int OutLeafsToSolid(node_t *node, settings::filltype_t filltype)
|
|||
static void SetOccupied_R(node_t *node, int dist)
|
||||
{
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
SetOccupied_R(node->children[0], dist);
|
||||
SetOccupied_R(node->children[1], dist);
|
||||
SetOccupied_R(node->children[0].get(), dist);
|
||||
SetOccupied_R(node->children[1].get(), dist);
|
||||
}
|
||||
|
||||
node->occupied = dist;
|
||||
|
|
@ -596,7 +597,7 @@ Special cases: structural fully covered by detail still needs to be marked "visi
|
|||
*/
|
||||
bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum)
|
||||
{
|
||||
node_t *node = tree->headnode;
|
||||
node_t *node = tree->headnode.get();
|
||||
|
||||
logging::print(logging::flag::PROGRESS, "---- {} ----\n", __func__);
|
||||
|
||||
|
|
@ -716,9 +717,9 @@ void FillBrushEntity(mapentity_t* entity, tree_t *tree, const int hullnum)
|
|||
logging::print(logging::flag::PROGRESS, "---- {} ----\n", __func__);
|
||||
|
||||
// Clear the outside filling state on all nodes
|
||||
ClearOccupied_r(tree->headnode);
|
||||
ClearOccupied_r(tree->headnode.get());
|
||||
|
||||
MarkBrushSidesInvisible(entity);
|
||||
|
||||
MarkVisibleBrushSides_R(tree->headnode);
|
||||
MarkVisibleBrushSides_R(tree->headnode.get());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ contentflags_t ClusterContents(const node_t *node)
|
|||
return node->contents;
|
||||
|
||||
return options.target_game->cluster_contents(
|
||||
ClusterContents(node->children[0]), ClusterContents(node->children[1]));
|
||||
ClusterContents(node->children[0].get()), ClusterContents(node->children[1].get()));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -193,9 +193,9 @@ void MakeHeadnodePortals(tree_t *tree)
|
|||
|
||||
p->winding = BaseWindingForPlane(pl);
|
||||
if (side)
|
||||
AddPortalToNodes(p, &tree->outside_node, tree->headnode);
|
||||
AddPortalToNodes(p, &tree->outside_node, tree->headnode.get());
|
||||
else
|
||||
AddPortalToNodes(p, tree->headnode, &tree->outside_node);
|
||||
AddPortalToNodes(p, tree->headnode.get(), &tree->outside_node);
|
||||
}
|
||||
|
||||
// clip the basewindings by all the other planes
|
||||
|
|
@ -222,6 +222,7 @@ Creates a winding from the given node plane, clipped by all parent nodes.
|
|||
|
||||
std::optional<winding_t> BaseWindingForNode(node_t *node)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
auto plane = map.planes.at(node->planenum);
|
||||
|
||||
std::optional<winding_t> w = BaseWindingForPlane(plane);
|
||||
|
|
@ -231,7 +232,7 @@ std::optional<winding_t> BaseWindingForNode(node_t *node)
|
|||
{
|
||||
plane = map.planes.at(np->planenum);
|
||||
|
||||
const planeside_t keep = (np->children[0] == node) ?
|
||||
const planeside_t keep = (np->children[0].get() == node) ?
|
||||
SIDE_FRONT : SIDE_BACK;
|
||||
|
||||
w = w->clip(plane, BASE_WINDING_EPSILON, false)[keep];
|
||||
|
|
@ -254,6 +255,8 @@ portals in the node.
|
|||
*/
|
||||
void MakeNodePortal(node_t *node, portalstats_t &stats)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
auto w = BaseWindingForNode(node);
|
||||
|
||||
// clip the portal by all the other portals in the node
|
||||
|
|
@ -291,7 +294,7 @@ void MakeNodePortal(node_t *node, portalstats_t &stats)
|
|||
new_portal->planenum = node->planenum;
|
||||
new_portal->onnode = node;
|
||||
new_portal->winding = w;
|
||||
AddPortalToNodes(new_portal, node->children[0], node->children[1]);
|
||||
AddPortalToNodes(new_portal, node->children[0].get(), node->children[1].get());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -304,9 +307,11 @@ children have portals instead of node.
|
|||
*/
|
||||
void SplitNodePortals(node_t *node, portalstats_t &stats)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
const auto plane = map.planes.at(node->planenum);
|
||||
node_t *f = node->children[0];
|
||||
node_t *b = node->children[1];
|
||||
node_t *f = node->children[0].get();
|
||||
node_t *b = node->children[1].get();
|
||||
|
||||
portal_t *next_portal = nullptr;
|
||||
for (portal_t *p = node->portals; p ; p = next_portal)
|
||||
|
|
@ -433,8 +438,8 @@ void MakeTreePortals_r(node_t *node, portalstats_t &stats)
|
|||
MakeNodePortal(node, stats);
|
||||
SplitNodePortals(node, stats);
|
||||
|
||||
MakeTreePortals_r(node->children[0], stats);
|
||||
MakeTreePortals_r(node->children[1], stats);
|
||||
MakeTreePortals_r(node->children[0].get(), stats);
|
||||
MakeTreePortals_r(node->children[1].get(), stats);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -444,14 +449,14 @@ MakeTreePortals
|
|||
*/
|
||||
void MakeTreePortals(tree_t *tree)
|
||||
{
|
||||
FreeTreePortals_r(tree->headnode);
|
||||
FreeTreePortals_r(tree->headnode.get());
|
||||
|
||||
AssertNoPortals(tree->headnode);
|
||||
AssertNoPortals(tree->headnode.get());
|
||||
|
||||
portalstats_t stats{};
|
||||
|
||||
MakeHeadnodePortals(tree);
|
||||
MakeTreePortals_r(tree->headnode, stats);
|
||||
MakeTreePortals_r(tree->headnode.get(), stats);
|
||||
}
|
||||
|
||||
void AssertNoPortals(node_t *node)
|
||||
|
|
@ -459,8 +464,8 @@ void AssertNoPortals(node_t *node)
|
|||
Q_assert(!node->portals);
|
||||
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
AssertNoPortals(node->children[0]);
|
||||
AssertNoPortals(node->children[1]);
|
||||
AssertNoPortals(node->children[0].get());
|
||||
AssertNoPortals(node->children[1].get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -475,8 +480,8 @@ void FreeTreePortals_r(node_t *node)
|
|||
portal_t *p, *nextp;
|
||||
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
FreeTreePortals_r(node->children[0]);
|
||||
FreeTreePortals_r(node->children[1]);
|
||||
FreeTreePortals_r(node->children[0].get());
|
||||
FreeTreePortals_r(node->children[1].get());
|
||||
}
|
||||
|
||||
for (p = node->portals; p; p = nextp) {
|
||||
|
|
@ -504,8 +509,8 @@ static void ApplyArea_r(node_t *node)
|
|||
node->area = map.c_areas;
|
||||
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
ApplyArea_r(node->children[0]);
|
||||
ApplyArea_r(node->children[1]);
|
||||
ApplyArea_r(node->children[0].get());
|
||||
ApplyArea_r(node->children[1].get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -513,10 +518,10 @@ static mapentity_t *AreanodeEntityForLeaf(node_t *node)
|
|||
{
|
||||
// if detail cluster, search the children recursively
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
if (auto *child0result = AreanodeEntityForLeaf(node->children[0]); child0result) {
|
||||
if (auto *child0result = AreanodeEntityForLeaf(node->children[0].get()); child0result) {
|
||||
return child0result;
|
||||
}
|
||||
return AreanodeEntityForLeaf(node->children[1]);
|
||||
return AreanodeEntityForLeaf(node->children[1].get());
|
||||
}
|
||||
|
||||
for (auto &brush : node->original_brushes) {
|
||||
|
|
@ -629,8 +634,8 @@ area set, flood fill out from there
|
|||
static void SetAreaPortalAreas_r(node_t *node)
|
||||
{
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
SetAreaPortalAreas_r(node->children[0]);
|
||||
SetAreaPortalAreas_r(node->children[1]);
|
||||
SetAreaPortalAreas_r(node->children[0].get());
|
||||
SetAreaPortalAreas_r(node->children[1].get());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -735,6 +740,8 @@ Finds a brush side to use for texturing the given portal
|
|||
*/
|
||||
static void FindPortalSide(portal_t *p)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
// decide which content change is strongest
|
||||
// solid > lava > water, etc
|
||||
contentflags_t viscontents = options.target_game->visible_contents(p->nodes[0]->contents, p->nodes[1]->contents);
|
||||
|
|
@ -799,8 +806,8 @@ static void MarkVisibleSides_r(node_t *node)
|
|||
{
|
||||
if (node->planenum != PLANENUM_LEAF)
|
||||
{
|
||||
MarkVisibleSides_r(node->children[0]);
|
||||
MarkVisibleSides_r(node->children[1]);
|
||||
MarkVisibleSides_r(node->children[0].get());
|
||||
MarkVisibleSides_r(node->children[1].get());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -840,5 +847,5 @@ void MarkVisibleSides(tree_t *tree, mapentity_t* entity)
|
|||
}
|
||||
|
||||
// set visible flags on the sides that are used by portals
|
||||
MarkVisibleSides_r (tree->headnode);
|
||||
MarkVisibleSides_r(tree->headnode.get());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,14 +48,16 @@ static void WriteFloat(std::ofstream &portalFile, vec_t v)
|
|||
|
||||
static void WritePortals_r(node_t *node, std::ofstream &portalFile, bool clusters)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
const portal_t *p, *next;
|
||||
std::optional<winding_t> w;
|
||||
int i, front, back;
|
||||
qplane3d plane2;
|
||||
|
||||
if (node->planenum != PLANENUM_LEAF && !node->detail_separator) {
|
||||
WritePortals_r(node->children[0], portalFile, clusters);
|
||||
WritePortals_r(node->children[1], portalFile, clusters);
|
||||
WritePortals_r(node->children[0].get(), portalFile, clusters);
|
||||
WritePortals_r(node->children[1].get(), portalFile, clusters);
|
||||
return;
|
||||
}
|
||||
if (node->contents.is_solid(options.target_game))
|
||||
|
|
@ -101,8 +103,8 @@ static void WritePortals_r(node_t *node, std::ofstream &portalFile, bool cluster
|
|||
static int WriteClusters_r(node_t *node, std::ofstream &portalFile, int viscluster)
|
||||
{
|
||||
if (node->planenum != PLANENUM_LEAF) {
|
||||
viscluster = WriteClusters_r(node->children[0], portalFile, viscluster);
|
||||
viscluster = WriteClusters_r(node->children[1], portalFile, viscluster);
|
||||
viscluster = WriteClusters_r(node->children[0].get(), portalFile, viscluster);
|
||||
viscluster = WriteClusters_r(node->children[1].get(), portalFile, viscluster);
|
||||
return viscluster;
|
||||
}
|
||||
if (node->contents.is_solid(options.target_game))
|
||||
|
|
@ -167,8 +169,8 @@ static void NumberLeafs_r(node_t *node, portal_state_t *state, int cluster)
|
|||
node->viscluster = cluster;
|
||||
CountPortals(node, state);
|
||||
}
|
||||
NumberLeafs_r(node->children[0], state, cluster);
|
||||
NumberLeafs_r(node->children[1], state, cluster);
|
||||
NumberLeafs_r(node->children[0].get(), state, cluster);
|
||||
NumberLeafs_r(node->children[1].get(), state, cluster);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -264,8 +266,8 @@ void CreateVisPortals_r(node_t *node, portalstats_t &stats)
|
|||
MakeNodePortal(node, stats);
|
||||
SplitNodePortals(node, stats);
|
||||
|
||||
CreateVisPortals_r(node->children[0], stats);
|
||||
CreateVisPortals_r(node->children[1], stats);
|
||||
CreateVisPortals_r(node->children[0].get(), stats);
|
||||
CreateVisPortals_r(node->children[1].get(), stats);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -279,16 +281,16 @@ void WritePortalFile(tree_t *tree)
|
|||
|
||||
portal_state_t state{};
|
||||
|
||||
FreeTreePortals_r(tree->headnode);
|
||||
FreeTreePortals_r(tree->headnode.get());
|
||||
|
||||
AssertNoPortals(tree->headnode);
|
||||
AssertNoPortals(tree->headnode.get());
|
||||
MakeHeadnodePortals(tree);
|
||||
|
||||
portalstats_t stats{};
|
||||
CreateVisPortals_r(tree->headnode, stats);
|
||||
CreateVisPortals_r(tree->headnode.get(), stats);
|
||||
|
||||
/* save portal file for vis tracing */
|
||||
WritePortalfile(tree->headnode, &state);
|
||||
WritePortalfile(tree->headnode.get(), &state);
|
||||
|
||||
logging::print(logging::flag::STAT, " {:8} vis leafs\n", state.num_visleafs);
|
||||
logging::print(logging::flag::STAT, " {:8} vis clusters\n", state.num_visclusters);
|
||||
|
|
|
|||
41
qbsp/qbsp.cc
41
qbsp/qbsp.cc
|
|
@ -40,6 +40,7 @@
|
|||
#include <qbsp/qbsp.hh>
|
||||
#include <qbsp/writebsp.hh>
|
||||
#include <qbsp/outside.hh>
|
||||
#include <qbsp/tree.hh>
|
||||
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
|
|
@ -283,8 +284,8 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node)
|
|||
return;
|
||||
}
|
||||
|
||||
ExportBrushList_r(entity, node->children[0]);
|
||||
ExportBrushList_r(entity, node->children[1]);
|
||||
ExportBrushList_r(entity, node->children[0].get());
|
||||
ExportBrushList_r(entity, node->children[1].get());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -297,6 +298,8 @@ against axial bounding boxes
|
|||
*/
|
||||
static std::vector<std::tuple<size_t, const side_t *>> AddBrushBevels(const bspbrush_t &b)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
// add already-present planes
|
||||
std::vector<std::tuple<size_t, const side_t *>> planes;
|
||||
|
||||
|
|
@ -579,11 +582,11 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
|||
// fill again so PruneNodes works
|
||||
MakeTreePortals(tree);
|
||||
FillOutside(entity, tree, hullnum);
|
||||
PruneNodes(tree->headnode);
|
||||
DetailToSolid(tree->headnode);
|
||||
PruneNodes(tree->headnode.get());
|
||||
DetailToSolid(tree->headnode.get());
|
||||
}
|
||||
}
|
||||
ExportClipNodes(entity, tree->headnode, hullnum);
|
||||
ExportClipNodes(entity, tree->headnode.get(), hullnum);
|
||||
|
||||
// fixme-brushbsp: return here?
|
||||
} else {
|
||||
|
|
@ -628,8 +631,8 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
|||
|
||||
// Area portals
|
||||
if (options.target_game->id == GAME_QUAKE_II) {
|
||||
FloodAreas(entity, tree->headnode);
|
||||
EmitAreaPortals(tree->headnode);
|
||||
FloodAreas(entity, tree->headnode.get());
|
||||
EmitAreaPortals(tree->headnode.get());
|
||||
}
|
||||
} else {
|
||||
FillBrushEntity(entity, tree, hullnum);
|
||||
|
|
@ -641,39 +644,39 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
|||
MakeTreePortals(tree);
|
||||
|
||||
MarkVisibleSides(tree, entity);
|
||||
MakeFaces(tree->headnode);
|
||||
MakeFaces(tree->headnode.get());
|
||||
|
||||
FreeTreePortals_r(tree->headnode);
|
||||
PruneNodes(tree->headnode);
|
||||
FreeTreePortals_r(tree->headnode.get());
|
||||
PruneNodes(tree->headnode.get());
|
||||
|
||||
if (hullnum <= 0 && entity == map.world_entity() && (!map.leakfile || options.keepprt.value())) {
|
||||
WritePortalFile(tree);
|
||||
}
|
||||
|
||||
// needs to come after any face creation
|
||||
MakeMarkFaces(entity, tree->headnode);
|
||||
MakeMarkFaces(entity, tree->headnode.get());
|
||||
|
||||
// convert detail leafs to solid (in case we didn't make the call above)
|
||||
DetailToSolid(tree->headnode);
|
||||
DetailToSolid(tree->headnode.get());
|
||||
|
||||
// fixme-brushbsp: prune nodes
|
||||
|
||||
if (!options.notjunc.value()) {
|
||||
TJunc(entity, tree->headnode);
|
||||
TJunc(entity, tree->headnode.get());
|
||||
}
|
||||
|
||||
if (options.objexport.value() && entity == map.world_entity()) {
|
||||
ExportObj_Nodes("pre_makefaceedges_plane_faces", tree->headnode);
|
||||
ExportObj_Marksurfaces("pre_makefaceedges_marksurfaces", tree->headnode);
|
||||
ExportObj_Nodes("pre_makefaceedges_plane_faces", tree->headnode.get());
|
||||
ExportObj_Marksurfaces("pre_makefaceedges_marksurfaces", tree->headnode.get());
|
||||
}
|
||||
|
||||
firstface = MakeFaceEdges(entity, tree->headnode);
|
||||
firstface = MakeFaceEdges(entity, tree->headnode.get());
|
||||
|
||||
if (options.target_game->id == GAME_QUAKE_II) {
|
||||
ExportBrushList(entity, tree->headnode);
|
||||
ExportBrushList(entity, tree->headnode.get());
|
||||
}
|
||||
|
||||
ExportDrawNodes(entity, tree->headnode, firstface);
|
||||
ExportDrawNodes(entity, tree->headnode.get(), firstface);
|
||||
}
|
||||
|
||||
FreeBrushes(entity);
|
||||
|
|
@ -763,6 +766,8 @@ hull sizes
|
|||
static void BSPX_Brushes_AddModel(
|
||||
struct bspxbrushes_s *ctx, int modelnum, std::vector<std::unique_ptr<bspbrush_t>> &brushes)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
|
||||
bspxbrushes_permodel permodel{1, modelnum};
|
||||
|
||||
for (auto &b : brushes) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <qbsp/brush.hh>
|
||||
#include <qbsp/brushbsp.hh>
|
||||
#include <qbsp/qbsp.hh>
|
||||
#include <qbsp/map.hh>
|
||||
#include <common/fs.hh>
|
||||
|
|
@ -870,7 +871,19 @@ TEST_CASE("merge", "[testmaps_q1]")
|
|||
const auto [bsp, bspx, prt] = LoadTestmapQ1("qbsp_merge.map");
|
||||
|
||||
REQUIRE_FALSE(prt.has_value());
|
||||
REQUIRE(6 == bsp.dfaces.size());
|
||||
REQUIRE(bsp.dfaces.size() >= 6);
|
||||
|
||||
// BrushBSP does a split through the middle first to keep the BSP balanced, which prevents
|
||||
// two of the side face from being merged
|
||||
REQUIRE(bsp.dfaces.size() <= 8);
|
||||
|
||||
const auto exp_bounds = aabb3d{{48,0,96}, {224,96,96}};
|
||||
|
||||
auto* top_face = BSP_FindFaceAtPoint(&bsp, &bsp.dmodels[0], {48,0,96}, {0,0,1});
|
||||
const auto top_winding = Face_Winding(&bsp, top_face);
|
||||
|
||||
CHECK(top_winding.bounds().mins() == exp_bounds.mins());
|
||||
CHECK(top_winding.bounds().maxs() == exp_bounds.maxs());
|
||||
}
|
||||
|
||||
TEST_CASE("tjunc_many_sided_face", "[testmaps_q1]")
|
||||
|
|
@ -1677,3 +1690,37 @@ TEST_CASE("winding", "[benchmark][.releaseonly]") {
|
|||
ankerl::nanobench::doNotOptimizeAway(temp);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE("BrushFromBounds") {
|
||||
map.reset();
|
||||
options.reset();
|
||||
options.worldextent.setValue(1024);
|
||||
|
||||
auto brush = BrushFromBounds({{2,2,2}, {32, 32, 32}});
|
||||
|
||||
CHECK(brush->sides.size() == 6);
|
||||
|
||||
const auto top_winding = winding_t{{2, 2, 32}, {2, 32, 32}, {32, 32, 32}, {32, 2, 32}};
|
||||
const auto bottom_winding = winding_t{{32, 2, 2},{32, 32, 2}, {2, 32, 2}, {2, 2, 2}};
|
||||
|
||||
int found = 0;
|
||||
|
||||
for (auto &side : brush->sides) {
|
||||
CHECK(side.w);
|
||||
|
||||
if (side.w.directional_equal(top_winding)) {
|
||||
found++;
|
||||
auto plane = Face_Plane(&side);
|
||||
CHECK(plane.normal == qvec3d{0,0,1});
|
||||
CHECK(plane.dist == 32);
|
||||
}
|
||||
|
||||
if (side.w.directional_equal(bottom_winding)) {
|
||||
found++;
|
||||
auto plane = Face_Plane(&side);
|
||||
CHECK(plane.normal == qvec3d{0,0,-1});
|
||||
CHECK(plane.dist == -2);
|
||||
}
|
||||
}
|
||||
CHECK(found == 2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -370,8 +370,8 @@ static void tjunc_count_r(node_t *node)
|
|||
cWVerts += f->w.size();
|
||||
}
|
||||
|
||||
tjunc_count_r(node->children[0]);
|
||||
tjunc_count_r(node->children[1]);
|
||||
tjunc_count_r(node->children[0].get());
|
||||
tjunc_count_r(node->children[1].get());
|
||||
}
|
||||
|
||||
static void tjunc_find_r(node_t *node)
|
||||
|
|
@ -383,8 +383,8 @@ static void tjunc_find_r(node_t *node)
|
|||
AddFaceEdges(f);
|
||||
}
|
||||
|
||||
tjunc_find_r(node->children[0]);
|
||||
tjunc_find_r(node->children[1]);
|
||||
tjunc_find_r(node->children[0].get());
|
||||
tjunc_find_r(node->children[1].get());
|
||||
}
|
||||
|
||||
static void tjunc_fix_r(node_t *node)
|
||||
|
|
@ -396,8 +396,8 @@ static void tjunc_fix_r(node_t *node)
|
|||
FixFaceEdges(face);
|
||||
}
|
||||
|
||||
tjunc_fix_r(node->children[0]);
|
||||
tjunc_fix_r(node->children[1]);
|
||||
tjunc_fix_r(node->children[0].get());
|
||||
tjunc_fix_r(node->children[1].get());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
10
qbsp/tree.cc
10
qbsp/tree.cc
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <common/vectorutils.hh>
|
||||
#include <qbsp/qbsp.hh>
|
||||
#include <qbsp/brush.hh>
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
|
@ -37,7 +38,6 @@ static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents)
|
|||
node->planenum = PLANENUM_LEAF;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
delete node->children[i];
|
||||
node->children[i] = nullptr;
|
||||
}
|
||||
for (auto *face : node->facelist) {
|
||||
|
|
@ -68,8 +68,8 @@ void DetailToSolid(node_t *node)
|
|||
*/
|
||||
return;
|
||||
} else {
|
||||
DetailToSolid(node->children[0]);
|
||||
DetailToSolid(node->children[1]);
|
||||
DetailToSolid(node->children[0].get());
|
||||
DetailToSolid(node->children[1].get());
|
||||
|
||||
// If both children are solid, we can merge the two leafs into one.
|
||||
// DarkPlaces has an assertion that fails if both children are
|
||||
|
|
@ -89,8 +89,8 @@ static void PruneNodes_R(node_t *node, int &count_pruned)
|
|||
return;
|
||||
}
|
||||
|
||||
PruneNodes_R(node->children[0], count_pruned);
|
||||
PruneNodes_R(node->children[1], count_pruned);
|
||||
PruneNodes_R(node->children[0].get(), count_pruned);
|
||||
PruneNodes_R(node->children[1].get(), count_pruned);
|
||||
|
||||
if (node->children[0]->planenum == PLANENUM_LEAF && node->children[0]->contents.is_solid(options.target_game) &&
|
||||
node->children[1]->planenum == PLANENUM_LEAF && node->children[1]->contents.is_solid(options.target_game)) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ using nlohmann::json;
|
|||
*/
|
||||
size_t ExportMapPlane(size_t planenum)
|
||||
{
|
||||
const auto lock = std::lock_guard(map_planes_lock);
|
||||
qbsp_plane_t &plane = map.planes.at(planenum);
|
||||
|
||||
if (plane.outputplanenum.has_value())
|
||||
|
|
@ -106,8 +107,8 @@ static size_t ExportClipNodes(mapentity_t *entity, node_t *node)
|
|||
const size_t nodenum = map.bsp.dclipnodes.size();
|
||||
map.bsp.dclipnodes.emplace_back();
|
||||
|
||||
const int child0 = ExportClipNodes(entity, node->children[0]);
|
||||
const int child1 = ExportClipNodes(entity, node->children[1]);
|
||||
const int child0 = ExportClipNodes(entity, node->children[0].get());
|
||||
const int child1 = ExportClipNodes(entity, node->children[1].get());
|
||||
|
||||
// Careful not to modify the vector while using this clipnode pointer
|
||||
bsp2_dclipnode_t &clipnode = map.bsp.dclipnodes[nodenum];
|
||||
|
|
@ -222,12 +223,12 @@ static void ExportDrawNodes(mapentity_t *entity, node_t *node)
|
|||
int32_t nextLeafIndex = static_cast<int32_t>(map.bsp.dleafs.size());
|
||||
const int32_t childnum = -(nextLeafIndex + 1);
|
||||
dnode->children[i] = childnum;
|
||||
ExportLeaf(entity, node->children[i]);
|
||||
ExportLeaf(entity, node->children[i].get());
|
||||
}
|
||||
} else {
|
||||
const int32_t childnum = static_cast<int32_t>(map.bsp.dnodes.size());
|
||||
dnode->children[i] = childnum;
|
||||
ExportDrawNodes(entity, node->children[i]);
|
||||
ExportDrawNodes(entity, node->children[i].get());
|
||||
|
||||
// Important: our dnode pointer may be invalid after the recursive call, if the vector got resized.
|
||||
// So re-set the pointer.
|
||||
|
|
|
|||
Loading…
Reference in New Issue