qbsp: move to unique_ptr<brush_t> vectors
This commit is contained in:
parent
0049449075
commit
893b0b080e
|
|
@ -33,6 +33,7 @@ struct brush_t
|
|||
* the BrushBSP will have this pointing back to the original brush in mapentity_t::brushes.
|
||||
*/
|
||||
brush_t *original;
|
||||
uint32_t file_order;
|
||||
aabb3d bounds;
|
||||
std::vector<face_t> faces;
|
||||
contentflags_t contents; /* BSP contents */
|
||||
|
|
|
|||
|
|
@ -21,14 +21,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <qbsp/brush.hh>
|
||||
|
||||
#include <common/qvec.hh>
|
||||
|
||||
#include <list>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
struct brush_t;
|
||||
struct face_t;
|
||||
|
||||
int MakeSkipTexinfo();
|
||||
|
|
@ -38,4 +37,4 @@ face_t *MirrorFace(const face_t *face);
|
|||
std::tuple<face_t *, face_t *> SplitFace(face_t *in, const qplane3d &split);
|
||||
void UpdateFaceSphere(face_t *in);
|
||||
bool BrushGE(const brush_t &a, const brush_t &b);
|
||||
std::vector<brush_t> ChopBrushes(const std::vector<brush_t> &input);
|
||||
std::vector<std::unique_ptr<brush_t>> ChopBrushes(const std::vector<std::unique_ptr<brush_t>> &input);
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <qbsp/brush.hh>
|
||||
#include <qbsp/qbsp.hh>
|
||||
|
||||
#include <common/bspfile.hh>
|
||||
#include <common/parser.hh>
|
||||
#include "common/cmdlib.hh"
|
||||
|
||||
|
|
@ -32,6 +33,8 @@
|
|||
#include <unordered_map>
|
||||
#include <list>
|
||||
|
||||
struct brush_t;
|
||||
|
||||
struct qbsp_plane_t : qplane3d
|
||||
{
|
||||
int type = 0;
|
||||
|
|
@ -96,7 +99,7 @@ public:
|
|||
std::vector<std::pair<std::string, std::string>> epairs;
|
||||
|
||||
aabb3d bounds;
|
||||
std::vector<brush_t> brushes;
|
||||
std::vector<std::unique_ptr<brush_t>> brushes;
|
||||
|
||||
int firstoutputfacenumber = -1;
|
||||
std::optional<size_t> outputmodelnumber = std::nullopt;
|
||||
|
|
@ -241,6 +244,6 @@ void ExportObj_Brushes(const std::string &filesuffix, const std::vector<const br
|
|||
void ExportObj_Nodes(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<brush_t> &list);
|
||||
void WriteBspBrushMap(const fs::path &name, const std::vector<std::unique_ptr<brush_t>> &list);
|
||||
|
||||
bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
class mapentity_t;
|
||||
struct node_t;
|
||||
|
||||
bool FillOutside(mapentity_t *entity, node_t *node, const int hullnum);
|
||||
std::vector<node_t *> FindOccupiedClusters(node_t *headnode);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,21 +21,21 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <qbsp/brush.hh>
|
||||
|
||||
#include <common/qvec.hh>
|
||||
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
|
||||
extern std::atomic<int> splitnodes;
|
||||
|
||||
struct brush_t;
|
||||
struct node_t;
|
||||
struct face_t;
|
||||
class mapentity_t;
|
||||
|
||||
void DetailToSolid(node_t *node);
|
||||
void PruneNodes(node_t *node);
|
||||
twosided<std::optional<brush_t>> SplitBrush(const brush_t &brush, const qplane3d &split);
|
||||
twosided<std::unique_ptr<brush_t>> SplitBrush(std::unique_ptr<brush_t> brush, const qplane3d &split);
|
||||
node_t *SolidBSP(mapentity_t *entity, bool midsplit);
|
||||
|
|
|
|||
|
|
@ -965,7 +965,7 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int
|
|||
} else {
|
||||
stats.liquid++;
|
||||
}
|
||||
dst->brushes.push_back(std::move(brush.value()));
|
||||
dst->brushes.push_back(std::make_unique<brush_t>(brush.value()));
|
||||
dst->bounds += brush->bounds;
|
||||
}
|
||||
|
||||
|
|
|
|||
100
qbsp/csg4.cc
100
qbsp/csg4.cc
|
|
@ -215,21 +215,11 @@ static void FreeFaces(std::list<face_t *> &facelist)
|
|||
|
||||
//==========================================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
BrushIndexInMap
|
||||
|
||||
Returns the index of the brush in the .map files.
|
||||
Only call with an "original" brush (from entity->brushes).
|
||||
Used for clipping priority.
|
||||
==================
|
||||
*/
|
||||
static int BrushIndexInMap(const mapentity_t *entity, const brush_t *brush)
|
||||
static std::vector<std::unique_ptr<brush_t>> SingleBrush(std::unique_ptr<brush_t> a)
|
||||
{
|
||||
Q_assert(brush >= entity->brushes.data());
|
||||
Q_assert(brush < (entity->brushes.data() + entity->brushes.size()));
|
||||
|
||||
return static_cast<int>(brush - entity->brushes.data());
|
||||
std::vector<std::unique_ptr<brush_t>> res;
|
||||
res.push_back(std::move(a));
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -239,30 +229,46 @@ SubtractBrush
|
|||
Returns the fragments from a - b
|
||||
==================
|
||||
*/
|
||||
std::vector<brush_t> SubtractBrush(const brush_t& a, const brush_t& b)
|
||||
static std::vector<std::unique_ptr<brush_t>> SubtractBrush(std::unique_ptr<brush_t> a, const brush_t& b)
|
||||
{
|
||||
// first, check if `a` is fully in front of _any_ of b's planes
|
||||
for (const auto &side : b.faces) {
|
||||
auto [front, back] = SplitBrush(a, Face_Plane(&side));
|
||||
if (front && !back) {
|
||||
// `a` is fully in front of this side of b, so they don't actually intersect
|
||||
return {a};
|
||||
// is `a` fully in front of `side`?
|
||||
bool fully_infront = true;
|
||||
|
||||
// fixme-brushbsp: factor this out somewhere
|
||||
for (const auto &a_face : a->faces) {
|
||||
for (const auto &a_point : a_face.w) {
|
||||
if (Face_Plane(&side).distance_to(a_point) < 0) {
|
||||
fully_infront = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fully_infront) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<brush_t> frontlist;
|
||||
std::vector<brush_t> unclassified{a};
|
||||
if (fully_infront) {
|
||||
// `a` is fully in front of this side of b, so they don't actually intersect
|
||||
return SingleBrush(std::move(a));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<brush_t>> frontlist;
|
||||
std::vector<std::unique_ptr<brush_t>> unclassified = SingleBrush(std::move(a));
|
||||
|
||||
for (const auto &side : b.faces) {
|
||||
std::vector<brush_t> new_unclassified;
|
||||
std::vector<std::unique_ptr<brush_t>> new_unclassified;
|
||||
|
||||
for (const auto &fragment : unclassified) {
|
||||
auto [front, back] = SplitBrush(fragment, Face_Plane(&side));
|
||||
for (auto &fragment : unclassified) {
|
||||
// destructively processing `unclassified` here
|
||||
auto [front, back] = SplitBrush(std::move(fragment), Face_Plane(&side));
|
||||
if (front) {
|
||||
frontlist.push_back(*front);
|
||||
frontlist.push_back(std::move(front));
|
||||
}
|
||||
if (back) {
|
||||
new_unclassified.push_back(*back);
|
||||
new_unclassified.push_back(std::move(back));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +290,7 @@ bool BrushGE(const brush_t& a, const brush_t& b)
|
|||
// same contents clip each other
|
||||
if (a.contents == b.contents && a.contents.clips_same_type()) {
|
||||
// map file order
|
||||
return &a > &b;
|
||||
return a.file_order > b.file_order;
|
||||
}
|
||||
|
||||
// only chop if at least one of the two contents is
|
||||
|
|
@ -298,7 +304,7 @@ bool BrushGE(const brush_t& a, const brush_t& b)
|
|||
|
||||
if (a_pri == b_pri) {
|
||||
// map file order
|
||||
return &a > &b;
|
||||
return a.file_order > b.file_order;
|
||||
}
|
||||
|
||||
return a_pri >= b_pri;
|
||||
|
|
@ -311,12 +317,13 @@ ChopBrushes
|
|||
Clips off any overlapping portions of brushes
|
||||
==================
|
||||
*/
|
||||
std::vector<brush_t> ChopBrushes(const std::vector<brush_t>& input)
|
||||
std::vector<std::unique_ptr<brush_t>> ChopBrushes(const std::vector<std::unique_ptr<brush_t>>& input)
|
||||
{
|
||||
logging::print(logging::flag::PROGRESS, "---- {} ----\n", __func__);
|
||||
|
||||
// output vector for the parallel_for
|
||||
std::vector<std::vector<brush_t>> brush_fragments;
|
||||
// each inner vector corresponds to a brush in `input`
|
||||
// (set up this way for thread safety)
|
||||
std::vector<std::vector<std::unique_ptr<brush_t>>> brush_fragments;
|
||||
brush_fragments.resize(input.size());
|
||||
|
||||
/*
|
||||
|
|
@ -327,26 +334,31 @@ std::vector<brush_t> ChopBrushes(const std::vector<brush_t>& input)
|
|||
*
|
||||
* The output of this is a face list for each brush called "outside"
|
||||
*/
|
||||
tbb::parallel_for(static_cast<size_t>(0), input.size(), [input, &brush_fragments](const size_t i) {
|
||||
const auto &brush = input[i];
|
||||
tbb::parallel_for(static_cast<size_t>(0), input.size(), [&](const size_t i) {
|
||||
const auto& brush = input[i];
|
||||
|
||||
// the fragments `brush` is chopped into
|
||||
std::vector<brush_t> brush_result{brush};
|
||||
std::vector<std::unique_ptr<brush_t>> brush_result = SingleBrush(
|
||||
// start with a copy of brush
|
||||
std::make_unique<brush_t>(*brush)
|
||||
);
|
||||
|
||||
for (auto &clipbrush : input) {
|
||||
if (&brush == &clipbrush) {
|
||||
if (brush == clipbrush) {
|
||||
continue;
|
||||
}
|
||||
if (brush.bounds.disjoint(clipbrush.bounds)) {
|
||||
if (brush->bounds.disjoint(clipbrush->bounds)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BrushGE(clipbrush, brush)) {
|
||||
std::vector<brush_t> new_result;
|
||||
if (BrushGE(*clipbrush, *brush)) {
|
||||
std::vector<std::unique_ptr<brush_t>> new_result;
|
||||
|
||||
// clipbrush is stronger. clip all existing fragments to clipbrush
|
||||
for (const auto ¤t_fragment : brush_result) {
|
||||
for (const auto &new_fragment : SubtractBrush(current_fragment, clipbrush)) {
|
||||
new_result.push_back(new_fragment);
|
||||
// clipbrush is stronger.
|
||||
// rebuild existing fragments in brush_result, cliping them to clipbrush
|
||||
for (auto ¤t_fragment : brush_result) {
|
||||
for (auto &new_fragment : SubtractBrush(std::move(current_fragment), *clipbrush)) {
|
||||
new_result.push_back(std::move(new_fragment));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -355,11 +367,11 @@ std::vector<brush_t> ChopBrushes(const std::vector<brush_t>& input)
|
|||
}
|
||||
|
||||
// save the result
|
||||
brush_fragments[i] = brush_result;
|
||||
brush_fragments[i] = std::move(brush_result);
|
||||
});
|
||||
|
||||
// Non parallel part:
|
||||
std::vector<brush_t> result;
|
||||
std::vector<std::unique_ptr<brush_t>> result;
|
||||
for (auto &fragment_list : brush_fragments) {
|
||||
for (auto &fragment : fragment_list) {
|
||||
result.push_back(std::move(fragment));
|
||||
|
|
|
|||
12
qbsp/map.cc
12
qbsp/map.cc
|
|
@ -2271,7 +2271,7 @@ WriteBspBrushMap
|
|||
from q3map
|
||||
==================
|
||||
*/
|
||||
void WriteBspBrushMap(const fs::path &name, const std::vector<brush_t> &list)
|
||||
void WriteBspBrushMap(const fs::path &name, const std::vector<std::unique_ptr<brush_t>> &list)
|
||||
{
|
||||
logging::print("writing {}\n", name);
|
||||
std::ofstream f(name);
|
||||
|
|
@ -2283,7 +2283,7 @@ void WriteBspBrushMap(const fs::path &name, const std::vector<brush_t> &list)
|
|||
|
||||
for (auto &brush : list) {
|
||||
fmt::print(f, "{{\n");
|
||||
for (auto &face : brush.faces) {
|
||||
for (auto &face : brush->faces) {
|
||||
// FIXME: Factor out this mess
|
||||
qbsp_plane_t plane = map.planes.at(face.planenum);
|
||||
|
||||
|
|
@ -2322,15 +2322,17 @@ from q3map
|
|||
*/
|
||||
static void TestExpandBrushes(const mapentity_t *src)
|
||||
{
|
||||
std::vector<brush_t> hull1brushes;
|
||||
std::vector<std::unique_ptr<brush_t>> hull1brushes;
|
||||
|
||||
for (int i = 0; i < src->nummapbrushes; i++) {
|
||||
const mapbrush_t *mapbrush = &src->mapbrush(i);
|
||||
std::optional<brush_t> hull1brush = LoadBrush(
|
||||
src, mapbrush, {CONTENTS_SOLID}, {}, rotation_t::none, options.target_game->id == GAME_QUAKE_II ? -1 : 1);
|
||||
|
||||
if (hull1brush)
|
||||
hull1brushes.emplace_back(std::move(hull1brush.value()));
|
||||
if (hull1brush) {
|
||||
hull1brushes.emplace_back(
|
||||
std::make_unique<brush_t>(std::move(*hull1brush)));
|
||||
}
|
||||
}
|
||||
|
||||
WriteBspBrushMap("expanded.map", hull1brushes);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
See file, 'COPYING', for details.
|
||||
*/
|
||||
|
||||
#include <qbsp/outside.hh>
|
||||
#include <qbsp/brush.hh>
|
||||
#include <qbsp/map.hh>
|
||||
#include <qbsp/portals.hh>
|
||||
#include <qbsp/qbsp.hh>
|
||||
|
|
@ -357,7 +359,7 @@ std::vector<node_t *> FindOccupiedClusters(node_t *headnode)
|
|||
static void MarkBrushSidesInvisible(mapentity_t *entity)
|
||||
{
|
||||
for (auto &brush : entity->brushes) {
|
||||
for (auto &face : brush.faces) {
|
||||
for (auto &face : brush->faces) {
|
||||
face.visible = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
// portals.c
|
||||
|
||||
#include <qbsp/brush.hh>
|
||||
#include <qbsp/portals.hh>
|
||||
#include <fstream>
|
||||
#include <fmt/ostream.h>
|
||||
|
|
|
|||
32
qbsp/qbsp.cc
32
qbsp/qbsp.cc
|
|
@ -349,12 +349,12 @@ static void ExportBrushList(mapentity_t *entity, node_t *node)
|
|||
brush_state = {};
|
||||
|
||||
for (auto &b : entity->brushes) {
|
||||
b.outputnumber = { static_cast<uint32_t>(map.bsp.dbrushes.size()) };
|
||||
b->outputnumber = {static_cast<uint32_t>(map.bsp.dbrushes.size())};
|
||||
|
||||
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});
|
||||
|
||||
auto bevels = AddBrushBevels(b);
|
||||
auto bevels = AddBrushBevels(*b);
|
||||
|
||||
for (auto &plane : bevels) {
|
||||
map.bsp.dbrushsides.push_back(
|
||||
|
|
@ -654,6 +654,11 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
|||
logging::print(logging::flag::PROGRESS, "---- Brush_LoadEntity ----\n");
|
||||
auto stats = Brush_LoadEntity(entity, hullnum);
|
||||
|
||||
// assign brush file order
|
||||
for (size_t i = 0; i < entity->brushes.size(); ++i) {
|
||||
entity->brushes[i]->file_order = i;
|
||||
}
|
||||
|
||||
entity->brushes = ChopBrushes(entity->brushes);
|
||||
|
||||
if (entity == map.world_entity() && hullnum == 0) {
|
||||
|
|
@ -880,13 +885,14 @@ Generates a submodel's direct brush information to a separate file, so the engin
|
|||
hull sizes
|
||||
*/
|
||||
|
||||
static void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, std::vector<brush_t> &brushes)
|
||||
static void BSPX_Brushes_AddModel(
|
||||
struct bspxbrushes_s *ctx, int modelnum, std::vector<std::unique_ptr<brush_t>> &brushes)
|
||||
{
|
||||
bspxbrushes_permodel permodel{1, modelnum};
|
||||
|
||||
for (auto &b : brushes) {
|
||||
permodel.numbrushes++;
|
||||
for (auto &f : b.faces) {
|
||||
for (auto &f : b->faces) {
|
||||
/*skip axial*/
|
||||
if (fabs(map.planes[f.planenum].normal[0]) == 1 || fabs(map.planes[f.planenum].normal[1]) == 1 ||
|
||||
fabs(map.planes[f.planenum].normal[2]) == 1)
|
||||
|
|
@ -907,7 +913,7 @@ static void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, std::
|
|||
for (auto &b : brushes) {
|
||||
bspxbrushes_perbrush perbrush{};
|
||||
|
||||
for (auto &f : b.faces) {
|
||||
for (auto &f : b->faces) {
|
||||
/*skip axial*/
|
||||
if (fabs(map.planes[f.planenum].normal[0]) == 1 || fabs(map.planes[f.planenum].normal[1]) == 1 ||
|
||||
fabs(map.planes[f.planenum].normal[2]) == 1)
|
||||
|
|
@ -915,9 +921,9 @@ static void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, std::
|
|||
perbrush.numfaces++;
|
||||
}
|
||||
|
||||
perbrush.bounds = b.bounds;
|
||||
perbrush.bounds = b->bounds;
|
||||
|
||||
switch (b.contents.native) {
|
||||
switch (b->contents.native) {
|
||||
// contents should match the engine.
|
||||
case CONTENTS_EMPTY: // really an error, but whatever
|
||||
case CONTENTS_SOLID: // these are okay
|
||||
|
|
@ -925,21 +931,21 @@ static void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, std::
|
|||
case CONTENTS_SLIME:
|
||||
case CONTENTS_LAVA:
|
||||
case CONTENTS_SKY:
|
||||
if (b.contents.is_clip()) {
|
||||
if (b->contents.is_clip()) {
|
||||
perbrush.contents = -8;
|
||||
} else {
|
||||
perbrush.contents = b.contents.native;
|
||||
perbrush.contents = b->contents.native;
|
||||
}
|
||||
break;
|
||||
// case CONTENTS_LADDER:
|
||||
// perbrush.contents = -16;
|
||||
// break;
|
||||
default: {
|
||||
if (b.contents.is_clip()) {
|
||||
if (b->contents.is_clip()) {
|
||||
perbrush.contents = -8;
|
||||
} else {
|
||||
logging::print("WARNING: Unknown contents: {}. Translating to solid.\n",
|
||||
b.contents.to_string(options.target_game));
|
||||
b->contents.to_string(options.target_game));
|
||||
perbrush.contents = CONTENTS_SOLID;
|
||||
}
|
||||
break;
|
||||
|
|
@ -948,7 +954,7 @@ static void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, std::
|
|||
|
||||
str <= perbrush;
|
||||
|
||||
for (auto &f : b.faces) {
|
||||
for (auto &f : b->faces) {
|
||||
/*skip axial*/
|
||||
if (fabs(map.planes[f.planenum].normal[0]) == 1 || fabs(map.planes[f.planenum].normal[1]) == 1 ||
|
||||
fabs(map.planes[f.planenum].normal[2]) == 1)
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ ChooseMidPlaneFromList
|
|||
The clipping hull BSP doesn't worry about avoiding splits
|
||||
==================
|
||||
*/
|
||||
static face_t *ChooseMidPlaneFromList(std::vector<brush_t> &brushes, const aabb3d &bounds)
|
||||
static face_t *ChooseMidPlaneFromList(std::vector<std::unique_ptr<brush_t>> &brushes, const aabb3d &bounds)
|
||||
{
|
||||
/* pick the plane that splits the least */
|
||||
vec_t bestaxialmetric = VECT_MAX;
|
||||
|
|
@ -307,11 +307,11 @@ static face_t *ChooseMidPlaneFromList(std::vector<brush_t> &brushes, const aabb3
|
|||
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
for (auto &brush : brushes) {
|
||||
if (brush.contents.is_detail() != (pass == 1)) {
|
||||
if (brush->contents.is_detail() != (pass == 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &face : brush.faces) {
|
||||
for (auto &face : brush->faces) {
|
||||
if (face.onnode)
|
||||
continue;
|
||||
if (!face.visible) {
|
||||
|
|
@ -363,7 +363,7 @@ The real BSP heuristic
|
|||
fixme-brushbsp: prefer splits that include a lot of brush sides?
|
||||
==================
|
||||
*/
|
||||
static face_t *ChoosePlaneFromList(std::vector<brush_t> &brushes, const aabb3d &bounds)
|
||||
static face_t *ChoosePlaneFromList(std::vector<std::unique_ptr<brush_t>> &brushes, const aabb3d &bounds)
|
||||
{
|
||||
/* pick the plane that splits the least */
|
||||
int minsplits = INT_MAX - 1;
|
||||
|
|
@ -373,11 +373,11 @@ static face_t *ChoosePlaneFromList(std::vector<brush_t> &brushes, const aabb3d &
|
|||
/* Two passes - exhaust all non-detail faces before details */
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
for (auto &brush : brushes) {
|
||||
if (brush.contents.is_detail() != (pass == 1)) {
|
||||
if (brush->contents.is_detail() != (pass == 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &face : brush.faces) {
|
||||
for (auto &face : brush->faces) {
|
||||
if (face.onnode) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -394,7 +394,7 @@ static face_t *ChoosePlaneFromList(std::vector<brush_t> &brushes, const aabb3d &
|
|||
// now check all of the other faces in `brushes` and count how many
|
||||
// would get split if we used `face` as the splitting plane
|
||||
for (auto &brush2 : brushes) {
|
||||
for (auto &face2 : brush2.faces) {
|
||||
for (auto &face2 : brush2->faces) {
|
||||
if (face2.planenum == face.planenum || face2.onnode)
|
||||
continue;
|
||||
if (!face2.visible)
|
||||
|
|
@ -458,13 +458,13 @@ returns NULL if the surface list can not be divided any more (a leaf)
|
|||
Called in parallel.
|
||||
==================
|
||||
*/
|
||||
static face_t *SelectPartition(std::vector<brush_t> &brushes)
|
||||
static face_t *SelectPartition(std::vector<std::unique_ptr<brush_t>> &brushes)
|
||||
{
|
||||
// calculate a bounding box of the entire surfaceset
|
||||
aabb3d bounds;
|
||||
|
||||
for (auto &brush : brushes) {
|
||||
bounds += brush.bounds;
|
||||
bounds += brush->bounds;
|
||||
}
|
||||
|
||||
// how much of the map are we partitioning?
|
||||
|
|
@ -610,20 +610,20 @@ vec_t BrushVolume(const brush_t &brush)
|
|||
================
|
||||
SplitBrush
|
||||
|
||||
Generates two new brushes, leaving the original
|
||||
unchanged
|
||||
Note, it's useful to take/return std::unique_ptr so it can quickly return the
|
||||
input.
|
||||
|
||||
https://github.com/id-Software/Quake-2-Tools/blob/master/bsp/qbsp3/brushbsp.c#L935
|
||||
================
|
||||
*/
|
||||
twosided<std::optional<brush_t>> SplitBrush(const brush_t &brush, const qplane3d &split)
|
||||
twosided<std::unique_ptr<brush_t>> SplitBrush(std::unique_ptr<brush_t> brush, const qplane3d &split)
|
||||
{
|
||||
twosided<std::optional<brush_t>> result;
|
||||
twosided<std::unique_ptr<brush_t>> result;
|
||||
|
||||
// check all points
|
||||
vec_t d_front = 0;
|
||||
vec_t d_back = 0;
|
||||
for (auto &face : brush.faces) {
|
||||
for (auto &face : brush->faces) {
|
||||
for (int j = 0; j < face.w.size(); j++) {
|
||||
vec_t d = qv::dot(face.w[j], split.normal) - split.dist;
|
||||
if (d > 0 && d > d_front)
|
||||
|
|
@ -634,18 +634,18 @@ twosided<std::optional<brush_t>> SplitBrush(const brush_t &brush, const qplane3d
|
|||
}
|
||||
if (d_front < 0.1) // PLANESIDE_EPSILON)
|
||||
{ // only on back
|
||||
result.back = {brush};
|
||||
result.back = std::move(brush);
|
||||
return result;
|
||||
}
|
||||
if (d_back > -0.1) // PLANESIDE_EPSILON)
|
||||
{ // only on front
|
||||
result.front = {brush};
|
||||
result.front = std::move(brush);
|
||||
return result;
|
||||
}
|
||||
|
||||
// create a new winding from the split plane
|
||||
auto w = std::optional<winding_t>{BaseWindingForPlane(split)};
|
||||
for (auto &face : brush.faces) {
|
||||
for (auto &face : brush->faces) {
|
||||
if (!w) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -654,11 +654,11 @@ twosided<std::optional<brush_t>> SplitBrush(const brush_t &brush, const qplane3d
|
|||
}
|
||||
|
||||
if (!w || WindingIsTiny(*w)) { // the brush isn't really split
|
||||
side_t side = BrushMostlyOnSide(brush, split);
|
||||
side_t side = BrushMostlyOnSide(*brush, split);
|
||||
if (side == SIDE_FRONT)
|
||||
result.front = {brush};
|
||||
result.front = std::move(brush);
|
||||
else
|
||||
result.back = {brush};
|
||||
result.back = std::move(brush);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -673,16 +673,16 @@ twosided<std::optional<brush_t>> SplitBrush(const brush_t &brush, const qplane3d
|
|||
// start with 2 empty brushes
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
result[i] = { brush_t{} };
|
||||
result[i]->original = brush.original;
|
||||
result[i] = std::make_unique<brush_t>();
|
||||
result[i]->original = brush->original;
|
||||
// fixme-brushbsp: add a brush_t copy constructor to make sure we get all fields
|
||||
result[i]->contents = brush.contents;
|
||||
result[i]->lmshift = brush.lmshift;
|
||||
result[i]->contents = brush->contents;
|
||||
result[i]->lmshift = brush->lmshift;
|
||||
}
|
||||
|
||||
// split all the current windings
|
||||
|
||||
for (const auto& face : brush.faces) {
|
||||
for (const auto &face : brush->faces) {
|
||||
auto cw = face.w.clip(split, 0 /*PLANESIDE_EPSILON*/);
|
||||
for (size_t j = 0; j < 2; j++) {
|
||||
if (!cw[j])
|
||||
|
|
@ -721,7 +721,7 @@ twosided<std::optional<brush_t>> SplitBrush(const brush_t &brush, const qplane3d
|
|||
}
|
||||
|
||||
if (result[i]->faces.size() < 3 || bogus) {
|
||||
result[i] = std::nullopt;
|
||||
result[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -731,10 +731,10 @@ twosided<std::optional<brush_t>> SplitBrush(const brush_t &brush, const qplane3d
|
|||
else
|
||||
logging::print("split not on both sides\n");
|
||||
if (result[0]) {
|
||||
result.front = {brush};
|
||||
result.front = std::move(brush);
|
||||
}
|
||||
if (result[1]) {
|
||||
result.back = {brush};
|
||||
result.back = std::move(brush);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -764,7 +764,7 @@ twosided<std::optional<brush_t>> SplitBrush(const brush_t &brush, const qplane3d
|
|||
for (i = 0; i < 2; i++) {
|
||||
v1 = BrushVolume(*result[i]);
|
||||
if (v1 < 1.0) {
|
||||
result[i] = std::nullopt;
|
||||
result[i] = nullptr;
|
||||
// qprintf ("tiny volume after clip\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -785,10 +785,10 @@ inline void DivideNodeBounds(node_t *node, const qbsp_plane_t &split)
|
|||
DivideBounds(node->bounds, split, node->children[0]->bounds, node->children[1]->bounds);
|
||||
}
|
||||
|
||||
static bool AllDetail(const std::vector<brush_t> &brushes)
|
||||
static bool AllDetail(const std::vector<std::unique_ptr<brush_t>> &brushes)
|
||||
{
|
||||
for (auto &brush : brushes) {
|
||||
if (!brush.contents.is_detail()) {
|
||||
if (!brush->contents.is_detail()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -818,18 +818,18 @@ original faces that have some fragment inside this leaf.
|
|||
Called in parallel.
|
||||
==================
|
||||
*/
|
||||
static void CreateLeaf(const std::vector<brush_t> &brushes, node_t *leafnode)
|
||||
static void CreateLeaf(std::vector<std::unique_ptr<brush_t>> brushes, node_t *leafnode)
|
||||
{
|
||||
leafnode->facelist.clear();
|
||||
leafnode->planenum = PLANENUM_LEAF;
|
||||
|
||||
leafnode->contents = options.target_game->create_empty_contents();
|
||||
for (auto &brush : brushes) {
|
||||
leafnode->contents = MergeContents(leafnode->contents, brush.contents);
|
||||
leafnode->contents = MergeContents(leafnode->contents, brush->contents);
|
||||
}
|
||||
for (auto &brush : brushes) {
|
||||
Q_assert(brush.original != nullptr);
|
||||
leafnode->original_brushes.push_back(brush.original);
|
||||
Q_assert(brush->original != nullptr);
|
||||
leafnode->original_brushes.push_back(brush->original);
|
||||
}
|
||||
|
||||
if (leafnode->contents.extended & CFLAGS_ILLUSIONARY_VISBLOCKER) {
|
||||
|
|
@ -859,14 +859,14 @@ PartitionBrushes
|
|||
Called in parallel.
|
||||
==================
|
||||
*/
|
||||
static void PartitionBrushes(std::vector<brush_t> brushes, node_t *node)
|
||||
static void PartitionBrushes(std::vector<std::unique_ptr<brush_t>> brushes, node_t *node)
|
||||
{
|
||||
face_t *split = SelectPartition(brushes);
|
||||
|
||||
if (split == nullptr) { // this is a leaf node
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
|
||||
CreateLeaf(brushes, node);
|
||||
CreateLeaf(std::move(brushes), node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -882,10 +882,11 @@ static void PartitionBrushes(std::vector<brush_t> brushes, node_t *node)
|
|||
DivideNodeBounds(node, splitplane);
|
||||
|
||||
// multiple surfaces, so split all the polysurfaces into front and back lists
|
||||
std::vector<brush_t> frontlist, backlist;
|
||||
std::vector<std::unique_ptr<brush_t>> frontlist, backlist;
|
||||
|
||||
for (auto &brush : brushes) {
|
||||
auto frags = SplitBrush(brush, splitplane);
|
||||
// NOTE: we're destroying `brushes` here with the std::move()
|
||||
auto frags = SplitBrush(std::move(brush), splitplane);
|
||||
|
||||
// mark faces which were used as a splitter
|
||||
for (auto &brushMaybe : frags) {
|
||||
|
|
@ -902,13 +903,13 @@ static void PartitionBrushes(std::vector<brush_t> brushes, node_t *node)
|
|||
if (frags.front->faces.empty()) {
|
||||
FError("Surface with no faces");
|
||||
}
|
||||
frontlist.emplace_back(std::move(*frags.front));
|
||||
frontlist.emplace_back(std::move(frags.front));
|
||||
}
|
||||
if (frags.back) {
|
||||
if (frags.back->faces.empty()) {
|
||||
FError("Surface with no faces");
|
||||
}
|
||||
backlist.emplace_back(std::move(*frags.back));
|
||||
backlist.emplace_back(std::move(frags.back));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -956,7 +957,7 @@ node_t *SolidBSP(mapentity_t *entity, bool midsplit)
|
|||
int visible_brush_sides = 0;
|
||||
int invisible_brush_sides = 0;
|
||||
for (const auto &brush : entity->brushes) {
|
||||
for (auto &side : brush.faces) {
|
||||
for (auto &side : brush->faces) {
|
||||
if (side.visible) {
|
||||
++visible_brush_sides;
|
||||
} else {
|
||||
|
|
@ -989,10 +990,10 @@ node_t *SolidBSP(mapentity_t *entity, bool midsplit)
|
|||
mapbrushes = entity->brushes.size();
|
||||
|
||||
// set the original pointers
|
||||
std::vector<brush_t> brushcopies;
|
||||
for (brush_t &original : entity->brushes) {
|
||||
brush_t copy = original;
|
||||
copy.original = &original;
|
||||
std::vector<std::unique_ptr<brush_t>> brushcopies;
|
||||
for (const auto &original : entity->brushes) {
|
||||
auto copy = std::make_unique<brush_t>(*original);
|
||||
copy->original = original.get();
|
||||
brushcopies.push_back(std::move(copy));
|
||||
}
|
||||
PartitionBrushes(std::move(brushcopies), headnode);
|
||||
|
|
|
|||
|
|
@ -702,13 +702,13 @@ void MakeVisibleFaces(mapentity_t* entity, node_t* headnode)
|
|||
c_nodefaces = 0;
|
||||
|
||||
for (auto &brush : entity->brushes) {
|
||||
for (auto &face : brush.faces) {
|
||||
for (auto &face : brush->faces) {
|
||||
if (!face.visible) {
|
||||
continue;
|
||||
}
|
||||
face_t *temp = CopyFace(&face);
|
||||
|
||||
AddFaceToTree_r(entity, temp, &brush, headnode);
|
||||
AddFaceToTree_r(entity, temp, brush.get(), headnode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <qbsp/brush.hh>
|
||||
#include <qbsp/qbsp.hh>
|
||||
#include <qbsp/map.hh>
|
||||
#include <common/fs.hh>
|
||||
|
|
|
|||
Loading…
Reference in New Issue