remove bspbrush_t::original; it is no longer required since mapbrush_t is what the output is being written to
use some explicit types (bspbrush_t::ptr for pointer, bspbrush_t::container for container of pointers, and bspbrush_t::make_ptr to create one) so that we can swap it out with different pointers easier later swap out bspbrush_t::ptr from unique_ptr to shared_ptr; it's not important yet, but it does not increase compilation time and will allow us to pass things to functions like SplitBrush without destroying the original as long as we still have a reference to it somewhere (important for ChopBrushes) add get_positive_plane to mapface_t instead of creating a whole copy of the bspbrush_t list, BrushBSP now just creates copies of the shared_ptrs which are then filtered down the tree; the originals are never modified by SplitBrushList and friends, only split into new brushes, so this is safe from what I can tell portals now directly reference the mapface_ts original_brushes now directly reference the mapbrush_ts early exit in `BrushBSP` if brush list is empty (moved to top)
This commit is contained in:
parent
faf9173f10
commit
097b564cc6
|
|
@ -22,13 +22,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <qbsp/winding.hh>
|
#include <qbsp/winding.hh>
|
||||||
#include <qbsp/qbsp.hh>
|
|
||||||
#include <common/aabb.hh>
|
#include <common/aabb.hh>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
class mapentity_t;
|
class mapentity_t;
|
||||||
struct maptexinfo_t;
|
struct maptexinfo_t;
|
||||||
struct mapface_t;
|
struct mapface_t;
|
||||||
|
struct qbsp_plane_t;
|
||||||
|
|
||||||
struct side_t
|
struct side_t
|
||||||
{
|
{
|
||||||
|
|
@ -51,11 +51,19 @@ class mapbrush_t;
|
||||||
|
|
||||||
struct bspbrush_t
|
struct bspbrush_t
|
||||||
{
|
{
|
||||||
|
using ptr = std::shared_ptr<bspbrush_t>;
|
||||||
|
using container = std::vector<ptr>;
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static inline ptr make_ptr(Args&& ...args)
|
||||||
|
{
|
||||||
|
return std::make_shared<bspbrush_t>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The brushes in main brush vectors are considered originals. Brush fragments created during
|
* The brushes in main brush vectors are considered originals. Brush fragments created during
|
||||||
* the BrushBSP will have this pointing back to the original brush in the list.
|
* the BrushBSP will have this pointing back to the original brush in the list.
|
||||||
*/
|
*/
|
||||||
bspbrush_t *original;
|
|
||||||
mapbrush_t *mapbrush;
|
mapbrush_t *mapbrush;
|
||||||
aabb3d bounds;
|
aabb3d bounds;
|
||||||
int side, testside; // side of node during construction
|
int side, testside; // side of node during construction
|
||||||
|
|
@ -67,10 +75,8 @@ struct bspbrush_t
|
||||||
|
|
||||||
bool update_bounds(bool warn_on_failures);
|
bool update_bounds(bool warn_on_failures);
|
||||||
|
|
||||||
std::unique_ptr<bspbrush_t> copy_unique() const;
|
ptr copy_unique() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
using bspbrush_vector_t = std::vector<std::unique_ptr<bspbrush_t>>;
|
|
||||||
|
|
||||||
std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, mapbrush_t *mapbrush, const contentflags_t &contents, const int hullnum);
|
std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, mapbrush_t *mapbrush, const contentflags_t &contents, const int hullnum);
|
||||||
bool CreateBrushWindings(bspbrush_t *brush);
|
bool CreateBrushWindings(bspbrush_t *brush);
|
||||||
|
|
@ -39,5 +39,5 @@ struct tree_t;
|
||||||
constexpr vec_t EDGE_LENGTH_EPSILON = 0.2;
|
constexpr vec_t EDGE_LENGTH_EPSILON = 0.2;
|
||||||
|
|
||||||
bool WindingIsTiny(const winding_t &w, double size = EDGE_LENGTH_EPSILON);
|
bool WindingIsTiny(const winding_t &w, double size = EDGE_LENGTH_EPSILON);
|
||||||
std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds);
|
bspbrush_t::ptr BrushFromBounds(const aabb3d &bounds);
|
||||||
std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, const bspbrush_vector_t &brushes, std::optional<bool> forced_quick_tree);
|
std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, const bspbrush_t::container &brushes, std::optional<bool> forced_quick_tree);
|
||||||
|
|
|
||||||
|
|
@ -37,4 +37,3 @@ std::unique_ptr<face_t> CopyFace(const face_t *in);
|
||||||
std::tuple<std::unique_ptr<face_t>, std::unique_ptr<face_t>> SplitFace(
|
std::tuple<std::unique_ptr<face_t>, std::unique_ptr<face_t>> SplitFace(
|
||||||
std::unique_ptr<face_t> in, const qplane3d &split);
|
std::unique_ptr<face_t> in, const qplane3d &split);
|
||||||
void UpdateFaceSphere(face_t *in);
|
void UpdateFaceSphere(face_t *in);
|
||||||
bspbrush_vector_t MakeBspBrushList(const bspbrush_vector_t &brushes);
|
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,9 @@ struct mapface_t
|
||||||
|
|
||||||
const texvecf &get_texvecs() const;
|
const texvecf &get_texvecs() const;
|
||||||
void set_texvecs(const texvecf &vecs);
|
void set_texvecs(const texvecf &vecs);
|
||||||
|
|
||||||
const qbsp_plane_t &get_plane() const;
|
const qbsp_plane_t &get_plane() const;
|
||||||
|
const qbsp_plane_t &get_positive_plane() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class brushformat_t
|
enum class brushformat_t
|
||||||
|
|
@ -344,7 +345,7 @@ qvec3d FixRotateOrigin(mapentity_t *entity);
|
||||||
constexpr int HULL_COLLISION = -1;
|
constexpr int HULL_COLLISION = -1;
|
||||||
|
|
||||||
/* Create BSP brushes from map brushes */
|
/* Create BSP brushes from map brushes */
|
||||||
void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_vector_t &brushes);
|
void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_t::container &brushes);
|
||||||
|
|
||||||
std::list<face_t *> CSGFace(
|
std::list<face_t *> CSGFace(
|
||||||
face_t *srcface, const mapentity_t *srcentity, const bspbrush_t *srcbrush, const node_t *srcnode);
|
face_t *srcface, const mapentity_t *srcentity, const bspbrush_t *srcbrush, const node_t *srcnode);
|
||||||
|
|
@ -366,6 +367,6 @@ void ExportObj_Brushes(const std::string &filesuffix, const std::vector<const bs
|
||||||
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);
|
||||||
|
|
||||||
void WriteBspBrushMap(const fs::path &name, const std::vector<std::unique_ptr<bspbrush_t>> &list);
|
void WriteBspBrushMap(const fs::path &name, const bspbrush_t::container &list);
|
||||||
|
|
||||||
bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec);
|
bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec);
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class mapentity_t;
|
||||||
struct node_t;
|
struct node_t;
|
||||||
struct tree_t;
|
struct tree_t;
|
||||||
|
|
||||||
bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes);
|
bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_t::container &brushes);
|
||||||
std::vector<node_t *> FindOccupiedClusters(node_t *headnode);
|
std::vector<node_t *> FindOccupiedClusters(node_t *headnode);
|
||||||
|
|
||||||
void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes);
|
void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_t::container &brushes);
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ struct portal_t
|
||||||
std::unique_ptr<winding_t> winding;
|
std::unique_ptr<winding_t> winding;
|
||||||
|
|
||||||
bool sidefound; // false if ->side hasn't been checked
|
bool sidefound; // false if ->side hasn't been checked
|
||||||
side_t *sides[2]; // [0] = the brush side visible on nodes[0] - it could come from a brush in nodes[1]. NULL =
|
mapface_t *sides[2]; // [0] = the brush side visible on nodes[0] - it could come from a brush in nodes[1]. NULL =
|
||||||
// non-visible
|
// non-visible
|
||||||
face_t *face[2]; // output face in bsp file
|
face_t *face[2]; // output face in bsp file
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -78,4 +78,4 @@ std::list<std::unique_ptr<buildportal_t>> MakeHeadnodePortals(tree_t *tree);
|
||||||
void MakePortalsFromBuildportals(tree_t *tree, std::list<std::unique_ptr<buildportal_t>> buildportals);
|
void MakePortalsFromBuildportals(tree_t *tree, std::list<std::unique_ptr<buildportal_t>> buildportals);
|
||||||
void EmitAreaPortals(node_t *headnode);
|
void EmitAreaPortals(node_t *headnode);
|
||||||
void FloodAreas(mapentity_t *entity, node_t *headnode);
|
void FloodAreas(mapentity_t *entity, node_t *headnode);
|
||||||
void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_vector_t &brushes);
|
void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_t::container &brushes);
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
#include <common/aabb.hh>
|
#include <common/aabb.hh>
|
||||||
#include <common/settings.hh>
|
#include <common/settings.hh>
|
||||||
#include <common/fs.hh>
|
#include <common/fs.hh>
|
||||||
|
#include <qbsp/brush.hh>
|
||||||
|
|
||||||
enum texcoord_style_t
|
enum texcoord_style_t
|
||||||
{
|
{
|
||||||
|
|
@ -633,7 +634,7 @@ struct node_t
|
||||||
aabb3d bounds; // bounding volume, not just points inside
|
aabb3d bounds; // bounding volume, not just points inside
|
||||||
node_t *parent;
|
node_t *parent;
|
||||||
// this is also a bounding volume like `bounds`
|
// this is also a bounding volume like `bounds`
|
||||||
std::unique_ptr<bspbrush_t> volume; // one for each leaf/node
|
bspbrush_t::ptr volume; // one for each leaf/node
|
||||||
bool is_leaf = false;
|
bool is_leaf = false;
|
||||||
|
|
||||||
// information for decision nodes
|
// information for decision nodes
|
||||||
|
|
@ -662,7 +663,7 @@ struct node_t
|
||||||
uint32_t firstleafbrush; // Q2
|
uint32_t firstleafbrush; // Q2
|
||||||
uint32_t numleafbrushes;
|
uint32_t numleafbrushes;
|
||||||
int32_t area;
|
int32_t area;
|
||||||
std::vector<bspbrush_t *> original_brushes;
|
std::vector<mapbrush_t *> original_brushes;
|
||||||
};
|
};
|
||||||
|
|
||||||
void InitQBSP(int argc, const char **argv);
|
void InitQBSP(int argc, const char **argv);
|
||||||
|
|
|
||||||
|
|
@ -40,14 +40,12 @@ const qbsp_plane_t &side_t::get_plane() const
|
||||||
|
|
||||||
const qbsp_plane_t &side_t::get_positive_plane() const
|
const qbsp_plane_t &side_t::get_positive_plane() const
|
||||||
{
|
{
|
||||||
auto &p = map.get_plane(planenum & ~1);
|
return map.get_plane(planenum & ~1);
|
||||||
Q_assert(p.get_normal()[(int) p.get_type() % 3] > 0);
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<bspbrush_t> bspbrush_t::copy_unique() const
|
bspbrush_t::ptr bspbrush_t::copy_unique() const
|
||||||
{
|
{
|
||||||
return std::make_unique<bspbrush_t>(*this);
|
return bspbrush_t::make_ptr(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -347,7 +345,7 @@ std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, mapbrush_t *mapbrush
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
static void Brush_LoadEntity(mapentity_t *dst, mapentity_t *src, const int hullnum, content_stats_base_t &stats, bspbrush_vector_t &brushes)
|
static void Brush_LoadEntity(mapentity_t *dst, mapentity_t *src, const int hullnum, content_stats_base_t &stats, bspbrush_t::container &brushes)
|
||||||
{
|
{
|
||||||
// _omitbrushes 1 just discards all brushes in the entity.
|
// _omitbrushes 1 just discards all brushes in the entity.
|
||||||
// could be useful for geometry guides, selective compilation, etc.
|
// could be useful for geometry guides, selective compilation, etc.
|
||||||
|
|
@ -515,7 +513,7 @@ hullnum HULL_COLLISION should contain ALL brushes. (used by BSPX_CreateBrushList
|
||||||
hullnum 0 does not contain clip brushes.
|
hullnum 0 does not contain clip brushes.
|
||||||
============
|
============
|
||||||
*/
|
*/
|
||||||
void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_vector_t &brushes)
|
void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_t::container &brushes)
|
||||||
{
|
{
|
||||||
logging::funcheader();
|
logging::funcheader();
|
||||||
|
|
||||||
|
|
|
||||||
119
qbsp/brushbsp.cc
119
qbsp/brushbsp.cc
|
|
@ -79,9 +79,9 @@ BrushFromBounds
|
||||||
Creates a new axial brush
|
Creates a new axial brush
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds)
|
bspbrush_t::ptr BrushFromBounds(const aabb3d &bounds)
|
||||||
{
|
{
|
||||||
auto b = std::make_unique<bspbrush_t>();
|
auto b = bspbrush_t::make_ptr();
|
||||||
|
|
||||||
b->sides.resize(6);
|
b->sides.resize(6);
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
|
|
@ -377,7 +377,7 @@ Creates a leaf node.
|
||||||
Called in parallel.
|
Called in parallel.
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
static void LeafNode(node_t *leafnode, std::vector<std::unique_ptr<bspbrush_t>> brushes, bspstats_t &stats)
|
static void LeafNode(node_t *leafnode, bspbrush_t::container brushes, bspstats_t &stats)
|
||||||
{
|
{
|
||||||
leafnode->facelist.clear();
|
leafnode->facelist.clear();
|
||||||
leafnode->is_leaf = true;
|
leafnode->is_leaf = true;
|
||||||
|
|
@ -387,8 +387,8 @@ static void LeafNode(node_t *leafnode, std::vector<std::unique_ptr<bspbrush_t>>
|
||||||
leafnode->contents = qbsp_options.target_game->combine_contents(leafnode->contents, brush->contents);
|
leafnode->contents = qbsp_options.target_game->combine_contents(leafnode->contents, brush->contents);
|
||||||
}
|
}
|
||||||
for (auto &brush : brushes) {
|
for (auto &brush : brushes) {
|
||||||
Q_assert(brush->original != nullptr);
|
Q_assert(brush->mapbrush != nullptr);
|
||||||
leafnode->original_brushes.push_back(brush->original);
|
leafnode->original_brushes.push_back(brush->mapbrush);
|
||||||
}
|
}
|
||||||
|
|
||||||
qbsp_options.target_game->count_contents_in_stats(leafnode->contents, *stats.leafstats);
|
qbsp_options.target_game->count_contents_in_stats(leafnode->contents, *stats.leafstats);
|
||||||
|
|
@ -434,10 +434,10 @@ input.
|
||||||
https://github.com/id-Software/Quake-2-Tools/blob/master/bsp/qbsp3/brushbsp.c#L935
|
https://github.com/id-Software/Quake-2-Tools/blob/master/bsp/qbsp3/brushbsp.c#L935
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static twosided<std::unique_ptr<bspbrush_t>> SplitBrush(std::unique_ptr<bspbrush_t> brush, size_t planenum, bspstats_t &stats)
|
static twosided<bspbrush_t::ptr> SplitBrush(bspbrush_t::ptr brush, size_t planenum, bspstats_t &stats)
|
||||||
{
|
{
|
||||||
const qplane3d &split = map.planes[planenum];
|
const qplane3d &split = map.planes[planenum];
|
||||||
twosided<std::unique_ptr<bspbrush_t>> result;
|
twosided<bspbrush_t::ptr> result;
|
||||||
|
|
||||||
// check all points
|
// check all points
|
||||||
vec_t d_front = 0;
|
vec_t d_front = 0;
|
||||||
|
|
@ -493,7 +493,7 @@ static twosided<std::unique_ptr<bspbrush_t>> SplitBrush(std::unique_ptr<bspbrush
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
result[i] = std::make_unique<bspbrush_t>();
|
result[i] = std::make_unique<bspbrush_t>();
|
||||||
result[i]->original = brush->original;
|
result[i]->mapbrush = brush->mapbrush;
|
||||||
// fixme-brushbsp: add a bspbrush_t copy constructor to make sure we get all fields
|
// fixme-brushbsp: add a bspbrush_t copy constructor to make sure we get all fields
|
||||||
result[i]->contents = brush->contents;
|
result[i]->contents = brush->contents;
|
||||||
result[i]->sides.reserve(brush->sides.size() + 1);
|
result[i]->sides.reserve(brush->sides.size() + 1);
|
||||||
|
|
@ -695,7 +695,7 @@ ChooseMidPlaneFromList
|
||||||
The clipping hull BSP doesn't worry about avoiding splits
|
The clipping hull BSP doesn't worry about avoiding splits
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
static std::optional<size_t> ChooseMidPlaneFromList(const std::vector<std::unique_ptr<bspbrush_t>> &brushes, const node_t *node, bspstats_t &stats)
|
static std::optional<size_t> ChooseMidPlaneFromList(const bspbrush_t::container &brushes, const node_t *node, bspstats_t &stats)
|
||||||
{
|
{
|
||||||
vec_t bestaxialmetric = VECT_MAX;
|
vec_t bestaxialmetric = VECT_MAX;
|
||||||
std::optional<size_t> bestaxialplane;
|
std::optional<size_t> bestaxialplane;
|
||||||
|
|
@ -750,7 +750,7 @@ Using heuristics, chooses a plane to partition the brushes with.
|
||||||
Returns nullopt if there are no valid planes to split with.
|
Returns nullopt if there are no valid planes to split with.
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static std::optional<size_t> SelectSplitPlane(const std::vector<std::unique_ptr<bspbrush_t>> &brushes, node_t *node, std::optional<bool> forced_quick_tree, bspstats_t &stats)
|
static std::optional<size_t> SelectSplitPlane(const bspbrush_t::container &brushes, node_t *node, std::optional<bool> forced_quick_tree, bspstats_t &stats)
|
||||||
{
|
{
|
||||||
// no brushes left to split, so we can't use any plane.
|
// no brushes left to split, so we can't use any plane.
|
||||||
if (!brushes.size()) {
|
if (!brushes.size()) {
|
||||||
|
|
@ -803,9 +803,9 @@ static std::optional<size_t> SelectSplitPlane(const std::vector<std::unique_ptr<
|
||||||
constexpr int numpasses = 4;
|
constexpr int numpasses = 4;
|
||||||
for (int pass = 0; pass < numpasses; pass++) {
|
for (int pass = 0; pass < numpasses; pass++) {
|
||||||
for (auto &brush : brushes) {
|
for (auto &brush : brushes) {
|
||||||
if ((pass & 1) && !brush->original->contents.is_any_detail(qbsp_options.target_game))
|
if ((pass & 1) && !brush->mapbrush->contents.is_any_detail(qbsp_options.target_game))
|
||||||
continue;
|
continue;
|
||||||
if (!(pass & 1) && brush->original->contents.is_any_detail(qbsp_options.target_game))
|
if (!(pass & 1) && brush->mapbrush->contents.is_any_detail(qbsp_options.target_game))
|
||||||
continue;
|
continue;
|
||||||
for (auto &side : brush->sides) {
|
for (auto &side : brush->sides) {
|
||||||
if (side.bevel)
|
if (side.bevel)
|
||||||
|
|
@ -926,10 +926,10 @@ static std::optional<size_t> SelectSplitPlane(const std::vector<std::unique_ptr<
|
||||||
SplitBrushList
|
SplitBrushList
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static std::array<std::vector<std::unique_ptr<bspbrush_t>>, 2> SplitBrushList(
|
static std::array<bspbrush_t::container, 2> SplitBrushList(
|
||||||
std::vector<std::unique_ptr<bspbrush_t>> brushes, size_t planenum, bspstats_t &stats)
|
bspbrush_t::container brushes, size_t planenum, bspstats_t &stats)
|
||||||
{
|
{
|
||||||
std::array<std::vector<std::unique_ptr<bspbrush_t>>, 2> result;
|
std::array<bspbrush_t::container, 2> result;
|
||||||
|
|
||||||
for (auto &brush : brushes) {
|
for (auto &brush : brushes) {
|
||||||
int sides = brush->side;
|
int sides = brush->side;
|
||||||
|
|
@ -979,7 +979,7 @@ BuildTree_r
|
||||||
Called in parallel.
|
Called in parallel.
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
static void BuildTree_r(tree_t *tree, node_t *node, std::vector<std::unique_ptr<bspbrush_t>> brushes, std::optional<bool> forced_quick_tree, bspstats_t &stats)
|
static void BuildTree_r(tree_t *tree, node_t *node, bspbrush_t::container brushes, std::optional<bool> forced_quick_tree, bspstats_t &stats)
|
||||||
{
|
{
|
||||||
// find the best plane to use as a splitter
|
// find the best plane to use as a splitter
|
||||||
auto bestplane = SelectSplitPlane(brushes, node, forced_quick_tree, stats);
|
auto bestplane = SelectSplitPlane(brushes, node, forced_quick_tree, stats);
|
||||||
|
|
@ -1021,10 +1021,10 @@ static void BuildTree_r(tree_t *tree, node_t *node, std::vector<std::unique_ptr<
|
||||||
}
|
}
|
||||||
|
|
||||||
// to save time/memory we can destroy node's volume at this point
|
// to save time/memory we can destroy node's volume at this point
|
||||||
auto children_volumes = SplitBrush(std::move(node->volume), bestplane.value(), stats);
|
auto children_volumes = SplitBrush(std::move(node->volume), bestplane.value(), stats);
|
||||||
node->volume = nullptr;
|
node->volume = nullptr;
|
||||||
node->children[0]->volume = std::move(children_volumes[0]);
|
node->children[0]->volume = std::move(children_volumes[0]);
|
||||||
node->children[1]->volume = std::move(children_volumes[1]);
|
node->children[1]->volume = std::move(children_volumes[1]);
|
||||||
|
|
||||||
// recursively process children
|
// recursively process children
|
||||||
tbb::task_group g;
|
tbb::task_group g;
|
||||||
|
|
@ -1038,43 +1038,10 @@ static void BuildTree_r(tree_t *tree, node_t *node, std::vector<std::unique_ptr<
|
||||||
BrushBSP
|
BrushBSP
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
static std::unique_ptr<tree_t> BrushBSP_internal(mapentity_t *entity, std::vector<std::unique_ptr<bspbrush_t>> brushlist, std::optional<bool> forced_quick_tree)
|
std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, const bspbrush_t::container &brushlist, std::optional<bool> forced_quick_tree)
|
||||||
{
|
{
|
||||||
auto tree = std::make_unique<tree_t>();
|
auto tree = std::make_unique<tree_t>();
|
||||||
|
|
||||||
size_t c_faces = 0;
|
|
||||||
size_t c_nonvisfaces = 0;
|
|
||||||
size_t c_brushes = 0;
|
|
||||||
|
|
||||||
for (const auto &b : brushlist) {
|
|
||||||
c_brushes++;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// fixme-brushbsp: why does this just print and do nothing? should
|
|
||||||
// the brush be removed?
|
|
||||||
double volume = BrushVolume(*b);
|
|
||||||
if (volume < qbsp_options.microvolume.value()) {
|
|
||||||
logging::print("WARNING: {}: microbrush\n",
|
|
||||||
b->original->mapbrush->line);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (side_t &side : b->sides) {
|
|
||||||
if (side.bevel)
|
|
||||||
continue;
|
|
||||||
if (!side.w)
|
|
||||||
continue;
|
|
||||||
if (side.onnode)
|
|
||||||
continue;
|
|
||||||
if (side.source->visible)
|
|
||||||
c_faces++;
|
|
||||||
else
|
|
||||||
c_nonvisfaces++;
|
|
||||||
}
|
|
||||||
|
|
||||||
tree->bounds += b->bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (brushlist.empty()) {
|
if (brushlist.empty()) {
|
||||||
/*
|
/*
|
||||||
* We allow an entity to be constructed with no visible brushes
|
* We allow an entity to be constructed with no visible brushes
|
||||||
|
|
@ -1102,20 +1069,52 @@ static std::unique_ptr<tree_t> BrushBSP_internal(mapentity_t *entity, std::vecto
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t c_faces = 0;
|
||||||
|
size_t c_nonvisfaces = 0;
|
||||||
|
size_t c_brushes = 0;
|
||||||
|
|
||||||
|
for (const auto &b : brushlist) {
|
||||||
|
c_brushes++;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// fixme-brushbsp: why does this just print and do nothing? should
|
||||||
|
// the brush be removed?
|
||||||
|
double volume = BrushVolume(*b);
|
||||||
|
if (volume < qbsp_options.microvolume.value()) {
|
||||||
|
logging::print("WARNING: {}: microbrush\n",
|
||||||
|
b->mapbrush->line);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (side_t &side : b->sides) {
|
||||||
|
if (side.bevel)
|
||||||
|
continue;
|
||||||
|
if (!side.w)
|
||||||
|
continue;
|
||||||
|
if (side.onnode)
|
||||||
|
continue;
|
||||||
|
if (side.source->visible)
|
||||||
|
c_faces++;
|
||||||
|
else
|
||||||
|
c_nonvisfaces++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree->bounds += b->bounds;
|
||||||
|
}
|
||||||
|
|
||||||
logging::print(logging::flag::STAT, " {:8} brushes\n", c_brushes);
|
logging::print(logging::flag::STAT, " {:8} brushes\n", c_brushes);
|
||||||
logging::print(logging::flag::STAT, " {:8} visible faces\n", c_faces);
|
logging::print(logging::flag::STAT, " {:8} visible faces\n", c_faces);
|
||||||
logging::print(logging::flag::STAT, " {:8} nonvisible faces\n", c_nonvisfaces);
|
logging::print(logging::flag::STAT, " {:8} nonvisible faces\n", c_nonvisfaces);
|
||||||
|
|
||||||
auto node = tree->create_node();
|
auto node = tree->create_node();
|
||||||
|
node->volume = BrushFromBounds(tree->bounds.grow(SIDESPACE));
|
||||||
node->volume = BrushFromBounds(tree->bounds.grow(SIDESPACE));
|
|
||||||
node->bounds = tree->bounds.grow(SIDESPACE);
|
node->bounds = tree->bounds.grow(SIDESPACE);
|
||||||
|
|
||||||
tree->headnode = node;
|
tree->headnode = node;
|
||||||
|
|
||||||
bspstats_t stats{};
|
bspstats_t stats{};
|
||||||
stats.leafstats = qbsp_options.target_game->create_content_stats();
|
stats.leafstats = qbsp_options.target_game->create_content_stats();
|
||||||
BuildTree_r(tree.get(), tree->headnode, std::move(brushlist), forced_quick_tree, stats);
|
BuildTree_r(tree.get(), tree->headnode, brushlist, forced_quick_tree, stats);
|
||||||
|
|
||||||
logging::print(logging::flag::STAT, " {:8} visible nodes\n", stats.c_nodes - stats.c_nonvis);
|
logging::print(logging::flag::STAT, " {:8} visible nodes\n", stats.c_nodes - stats.c_nonvis);
|
||||||
if (stats.c_nonvis) {
|
if (stats.c_nonvis) {
|
||||||
|
|
@ -1149,9 +1148,3 @@ static std::unique_ptr<tree_t> BrushBSP_internal(mapentity_t *entity, std::vecto
|
||||||
|
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, const std::vector<std::unique_ptr<bspbrush_t>> &brushlist, std::optional<bool> forced_quick_tree)
|
|
||||||
{
|
|
||||||
logging::funcheader();
|
|
||||||
return BrushBSP_internal(entity, MakeBspBrushList(brushlist), forced_quick_tree);
|
|
||||||
}
|
|
||||||
13
qbsp/csg.cc
13
qbsp/csg.cc
|
|
@ -120,16 +120,3 @@ std::tuple<std::unique_ptr<face_t>, std::unique_ptr<face_t>> SplitFace(
|
||||||
|
|
||||||
return {std::move(new_front), std::move(new_back)};
|
return {std::move(new_front), std::move(new_back)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<bspbrush_t>> MakeBspBrushList(const bspbrush_vector_t &brushes)
|
|
||||||
{
|
|
||||||
// set the original pointers
|
|
||||||
std::vector<std::unique_ptr<bspbrush_t>> brushcopies;
|
|
||||||
for (const auto &original : brushes) {
|
|
||||||
auto copy = original->copy_unique();
|
|
||||||
copy->original = original.get();
|
|
||||||
brushcopies.push_back(std::move(copy));
|
|
||||||
}
|
|
||||||
|
|
||||||
return brushcopies;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -472,7 +472,7 @@ see also FindPortalSide which populates p->side
|
||||||
*/
|
*/
|
||||||
static std::unique_ptr<face_t> FaceFromPortal(portal_t *p, bool pside)
|
static std::unique_ptr<face_t> FaceFromPortal(portal_t *p, bool pside)
|
||||||
{
|
{
|
||||||
side_t *side = p->sides[pside];
|
mapface_t *side = p->sides[pside];
|
||||||
if (!side)
|
if (!side)
|
||||||
return nullptr; // portal does not bridge different visible contents
|
return nullptr; // portal does not bridge different visible contents
|
||||||
|
|
||||||
|
|
@ -481,7 +481,7 @@ static std::unique_ptr<face_t> FaceFromPortal(portal_t *p, bool pside)
|
||||||
f->texinfo = side->texinfo;
|
f->texinfo = side->texinfo;
|
||||||
f->planenum = (side->planenum & ~1) | (pside ? 1 : 0);
|
f->planenum = (side->planenum & ~1) | (pside ? 1 : 0);
|
||||||
f->portal = p;
|
f->portal = p;
|
||||||
f->original_side = side->source;
|
f->original_side = side;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
bool make_face =
|
bool make_face =
|
||||||
|
|
|
||||||
|
|
@ -1554,6 +1554,11 @@ const qbsp_plane_t &mapface_t::get_plane() const
|
||||||
return map.get_plane(planenum);
|
return map.get_plane(planenum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const qbsp_plane_t &mapface_t::get_positive_plane() const
|
||||||
|
{
|
||||||
|
return map.get_plane(planenum & ~1);
|
||||||
|
}
|
||||||
|
|
||||||
bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec)
|
bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec)
|
||||||
{
|
{
|
||||||
// TODO: This doesn't match how light does it (TexSpaceToWorld)
|
// TODO: This doesn't match how light does it (TexSpaceToWorld)
|
||||||
|
|
@ -2798,7 +2803,7 @@ WriteBspBrushMap
|
||||||
from q3map
|
from q3map
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
void WriteBspBrushMap(const fs::path &name, const std::vector<std::unique_ptr<bspbrush_t>> &list)
|
void WriteBspBrushMap(const fs::path &name, const bspbrush_t::container &list)
|
||||||
{
|
{
|
||||||
std::shared_lock lock(map_planes_lock);
|
std::shared_lock lock(map_planes_lock);
|
||||||
|
|
||||||
|
|
@ -2845,7 +2850,7 @@ from q3map
|
||||||
*/
|
*/
|
||||||
static void TestExpandBrushes(mapentity_t *src)
|
static void TestExpandBrushes(mapentity_t *src)
|
||||||
{
|
{
|
||||||
std::vector<std::unique_ptr<bspbrush_t>> hull1brushes;
|
bspbrush_t::container hull1brushes;
|
||||||
|
|
||||||
for (auto &mapbrush : src->mapbrushes) {
|
for (auto &mapbrush : src->mapbrushes) {
|
||||||
auto hull1brush = LoadBrush(src, &mapbrush, {CONTENTS_SOLID},
|
auto hull1brush = LoadBrush(src, &mapbrush, {CONTENTS_SOLID},
|
||||||
|
|
|
||||||
|
|
@ -349,7 +349,7 @@ std::vector<node_t *> FindOccupiedClusters(node_t *headnode)
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
static void MarkBrushSidesInvisible(mapentity_t *entity, bspbrush_vector_t &brushes)
|
static void MarkBrushSidesInvisible(mapentity_t *entity, bspbrush_t::container &brushes)
|
||||||
{
|
{
|
||||||
for (auto &brush : brushes) {
|
for (auto &brush : brushes) {
|
||||||
for (auto &face : brush->sides) {
|
for (auto &face : brush->sides) {
|
||||||
|
|
@ -412,13 +412,13 @@ static void MarkVisibleBrushSides_R(node_t *node)
|
||||||
// optimized case: just mark the brush sides in the neighbouring
|
// optimized case: just mark the brush sides in the neighbouring
|
||||||
// leaf that are coplanar
|
// leaf that are coplanar
|
||||||
for (auto *brush : neighbour_leaf->original_brushes) {
|
for (auto *brush : neighbour_leaf->original_brushes) {
|
||||||
for (auto &side : brush->sides) {
|
for (auto &side : brush->faces) {
|
||||||
// fixme-brushbsp: should this be get_plane() ?
|
// fixme-brushbsp: should this be get_plane() ?
|
||||||
// fixme-brushbsp: planenum
|
// fixme-brushbsp: planenum
|
||||||
if (qv::epsilonEqual(side.get_positive_plane(), portal->plane)) {
|
if (qv::epsilonEqual(side.get_positive_plane(), portal->plane)) {
|
||||||
// we've found a brush side in an original brush in the neighbouring
|
// we've found a brush side in an original brush in the neighbouring
|
||||||
// leaf, on a portal to this (non-opaque) leaf, so mark it as visible.
|
// leaf, on a portal to this (non-opaque) leaf, so mark it as visible.
|
||||||
side.source->visible = true;
|
side.visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -600,7 +600,7 @@ get incorrectly marked as "invisible").
|
||||||
Special cases: structural fully covered by detail still needs to be marked "visible".
|
Special cases: structural fully covered by detail still needs to be marked "visible".
|
||||||
===========
|
===========
|
||||||
*/
|
*/
|
||||||
bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes)
|
bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_t::container &brushes)
|
||||||
{
|
{
|
||||||
node_t *node = tree->headnode;
|
node_t *node = tree->headnode;
|
||||||
|
|
||||||
|
|
@ -720,7 +720,7 @@ bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes)
|
void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_t::container &brushes)
|
||||||
{
|
{
|
||||||
logging::funcheader();
|
logging::funcheader();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -573,8 +573,8 @@ static mapentity_t *AreanodeEntityForLeaf(node_t *node)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &brush : node->original_brushes) {
|
for (auto &brush : node->original_brushes) {
|
||||||
if (brush->mapbrush->func_areaportal) {
|
if (brush->func_areaportal) {
|
||||||
return brush->mapbrush->func_areaportal;
|
return brush->func_areaportal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -791,8 +791,8 @@ static void FindPortalSide(portal_t *p)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// bestside[0] is the brushside visible on portal side[0] which is the positive side of the plane, always
|
// bestside[0] is the brushside visible on portal side[0] which is the positive side of the plane, always
|
||||||
side_t *bestside[2] = {nullptr, nullptr};
|
mapface_t *bestside[2] = {nullptr, nullptr};
|
||||||
side_t *exactside[2] = {nullptr, nullptr};
|
mapface_t *exactside[2] = {nullptr, nullptr};
|
||||||
float bestdot = 0;
|
float bestdot = 0;
|
||||||
const qbsp_plane_t &p1 = p->onnode->get_plane();
|
const qbsp_plane_t &p1 = p->onnode->get_plane();
|
||||||
|
|
||||||
|
|
@ -813,7 +813,7 @@ static void FindPortalSide(portal_t *p)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &side : brush->sides) {
|
for (auto &side : brush->faces) {
|
||||||
if (side.bevel)
|
if (side.bevel)
|
||||||
continue;
|
continue;
|
||||||
if ((side.planenum & ~1) == p->onnode->planenum) {
|
if ((side.planenum & ~1) == p->onnode->planenum) {
|
||||||
|
|
@ -899,7 +899,7 @@ static void MarkVisibleSides_r(node_t *node)
|
||||||
FindPortalSide(p);
|
FindPortalSide(p);
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
if (p->sides[i]) {
|
if (p->sides[i]) {
|
||||||
p->sides[i]->source->visible = true;
|
p->sides[i]->visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -911,7 +911,7 @@ MarkVisibleSides
|
||||||
|
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_vector_t &brushes)
|
void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_t::container &brushes)
|
||||||
{
|
{
|
||||||
logging::funcheader();
|
logging::funcheader();
|
||||||
|
|
||||||
|
|
|
||||||
11
qbsp/qbsp.cc
11
qbsp/qbsp.cc
|
|
@ -306,14 +306,13 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node)
|
||||||
node->firstleafbrush = map.bsp.dleafbrushes.size();
|
node->firstleafbrush = map.bsp.dleafbrushes.size();
|
||||||
for (auto &b : node->original_brushes) {
|
for (auto &b : node->original_brushes) {
|
||||||
|
|
||||||
if (!b->mapbrush->outputnumber.has_value()) {
|
if (!b->outputnumber.has_value()) {
|
||||||
// FIXME
|
b->outputnumber = {static_cast<uint32_t>(map.bsp.dbrushes.size())};
|
||||||
b->mapbrush->outputnumber = {static_cast<uint32_t>(map.bsp.dbrushes.size())};
|
|
||||||
|
|
||||||
dbrush_t &brush = map.bsp.dbrushes.emplace_back(
|
dbrush_t &brush = map.bsp.dbrushes.emplace_back(
|
||||||
dbrush_t{static_cast<int32_t>(map.bsp.dbrushsides.size()), 0, b->contents.native});
|
dbrush_t{static_cast<int32_t>(map.bsp.dbrushsides.size()), 0, b->contents.native});
|
||||||
|
|
||||||
for (auto &side : b->mapbrush->faces) {
|
for (auto &side : b->faces) {
|
||||||
map.bsp.dbrushsides.push_back(
|
map.bsp.dbrushsides.push_back(
|
||||||
{(uint32_t) ExportMapPlane(side.planenum), (int32_t)ExportMapTexinfo(side.texinfo)});
|
{(uint32_t) ExportMapPlane(side.planenum), (int32_t)ExportMapTexinfo(side.texinfo)});
|
||||||
brush.numsides++;
|
brush.numsides++;
|
||||||
|
|
@ -323,7 +322,7 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node)
|
||||||
brush_state.total_brushes++;
|
brush_state.total_brushes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
map.bsp.dleafbrushes.push_back(b->mapbrush->outputnumber.value());
|
map.bsp.dleafbrushes.push_back(b->outputnumber.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -442,7 +441,7 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
||||||
|
|
||||||
// reserve enough brushes; we would only make less,
|
// reserve enough brushes; we would only make less,
|
||||||
// never more
|
// never more
|
||||||
bspbrush_vector_t brushes;
|
bspbrush_t::container brushes;
|
||||||
brushes.reserve(entity->mapbrushes.size());
|
brushes.reserve(entity->mapbrushes.size());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,8 @@ static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents)
|
||||||
node->original_brushes = std::move(node->children[base]->original_brushes);
|
node->original_brushes = std::move(node->children[base]->original_brushes);
|
||||||
node->original_brushes.insert(node->original_brushes.end(), node->children[base ^ 1]->original_brushes.begin(), node->children[base ^ 1]->original_brushes.end());
|
node->original_brushes.insert(node->original_brushes.end(), node->children[base ^ 1]->original_brushes.begin(), node->children[base ^ 1]->original_brushes.end());
|
||||||
|
|
||||||
std::sort(node->original_brushes.begin(), node->original_brushes.end(), [](const bspbrush_t *a, const bspbrush_t *b) {
|
// sort by pointer (since mapbrush_t is in a flat vector)
|
||||||
return a->mapbrush < b->mapbrush;
|
std::sort(node->original_brushes.begin(), node->original_brushes.end());
|
||||||
});
|
|
||||||
auto unique = std::unique(node->original_brushes.begin(), node->original_brushes.end());
|
auto unique = std::unique(node->original_brushes.begin(), node->original_brushes.end());
|
||||||
node->original_brushes.erase(unique, node->original_brushes.end());
|
node->original_brushes.erase(unique, node->original_brushes.end());
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue