qbsp: initial ChopBrushes implementation
This commit is contained in:
parent
019b8cb9ed
commit
cb2268efdf
|
|
@ -21,10 +21,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <qbsp/brush.hh>
|
||||
|
||||
#include <common/qvec.hh>
|
||||
|
||||
#include <list>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
struct face_t;
|
||||
|
||||
|
|
@ -33,3 +36,4 @@ face_t *NewFaceFromFace(const face_t *in);
|
|||
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);
|
||||
std::vector<brush_t> ChopBrushes(const std::vector<brush_t> &input);
|
||||
|
|
|
|||
|
|
@ -21,8 +21,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <qbsp/brush.hh>
|
||||
|
||||
#include <common/qvec.hh>
|
||||
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <optional>
|
||||
|
||||
extern std::atomic<int> splitnodes;
|
||||
|
||||
|
|
@ -32,4 +37,5 @@ 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);
|
||||
node_t *SolidBSP(mapentity_t *entity, bool midsplit);
|
||||
|
|
|
|||
124
qbsp/csg4.cc
124
qbsp/csg4.cc
|
|
@ -23,6 +23,7 @@
|
|||
#include <qbsp/brush.hh>
|
||||
#include <qbsp/csg4.hh>
|
||||
#include <qbsp/map.hh>
|
||||
#include <qbsp/solidbsp.hh>
|
||||
#include <qbsp/qbsp.hh>
|
||||
|
||||
#include <atomic>
|
||||
|
|
@ -474,3 +475,126 @@ std::list<face_t *> CSGFace(face_t *srcface, const mapentity_t *srcentity, const
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SubtractBrush
|
||||
|
||||
Returns the fragments from a - b
|
||||
==================
|
||||
*/
|
||||
std::vector<brush_t> SubtractBrush(const 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};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<brush_t> frontlist;
|
||||
std::vector<brush_t> unclassified{a};
|
||||
|
||||
for (const auto &side : b.faces) {
|
||||
std::vector<brush_t> new_unclassified;
|
||||
|
||||
for (const auto &fragment : unclassified) {
|
||||
auto [front, back] = SplitBrush(fragment, Face_Plane(&side));
|
||||
if (front) {
|
||||
frontlist.push_back(*front);
|
||||
}
|
||||
if (back) {
|
||||
new_unclassified.push_back(*back);
|
||||
}
|
||||
}
|
||||
|
||||
unclassified = std::move(new_unclassified);
|
||||
}
|
||||
|
||||
return frontlist;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
BrushGE
|
||||
|
||||
Returns a >= b as far as brush clipping
|
||||
==================
|
||||
*/
|
||||
static bool BrushGE(const brush_t& a, const brush_t& b)
|
||||
{
|
||||
int32_t a_pri = a.contents.priority(options.target_game);
|
||||
int32_t b_pri = b.contents.priority(options.target_game);
|
||||
|
||||
return a_pri >= b_pri;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
ChopBrushes
|
||||
|
||||
Clips off any overlapping portions of brushes
|
||||
==================
|
||||
*/
|
||||
std::vector<brush_t> ChopBrushes(const std::vector<brush_t>& input)
|
||||
{
|
||||
logging::print(logging::flag::PROGRESS, "---- {} ----\n", __func__);
|
||||
|
||||
// output vector for the parallel_for
|
||||
std::vector<std::vector<brush_t>> brush_fragments;
|
||||
brush_fragments.resize(input.size());
|
||||
|
||||
/*
|
||||
* For each brush, clip away the parts that are inside other brushes.
|
||||
* Solid brushes override non-solid brushes.
|
||||
* brush => the brush to be clipped
|
||||
* clipbrush => the brush we are clipping against
|
||||
*
|
||||
* 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];
|
||||
// the fragments `brush` is chopped into
|
||||
std::vector<brush_t> brush_result{brush};
|
||||
|
||||
for (auto &clipbrush : input) {
|
||||
if (&brush == &clipbrush) {
|
||||
continue;
|
||||
}
|
||||
if (brush.bounds.disjoint(clipbrush.bounds)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BrushGE(clipbrush, brush)) {
|
||||
std::vector<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);
|
||||
}
|
||||
}
|
||||
|
||||
brush_result = std::move(new_result);
|
||||
}
|
||||
}
|
||||
|
||||
// save the result
|
||||
brush_fragments[i] = brush_result;
|
||||
});
|
||||
|
||||
// Non parallel part:
|
||||
std::vector<brush_t> result;
|
||||
for (auto &fragment_list : brush_fragments) {
|
||||
for (auto &fragment : fragment_list) {
|
||||
result.push_back(std::move(fragment));
|
||||
}
|
||||
}
|
||||
|
||||
logging::print(logging::flag::STAT, " {:8} brushes\n", input.size());
|
||||
logging::print(logging::flag::STAT, " {:8} chopped brushes\n", result.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <common/settings.hh>
|
||||
|
||||
#include <qbsp/brush.hh>
|
||||
#include <qbsp/csg4.hh>
|
||||
#include <qbsp/map.hh>
|
||||
#include <qbsp/merge.hh>
|
||||
#include <qbsp/portals.hh>
|
||||
|
|
@ -653,6 +654,8 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
|||
logging::print(logging::flag::PROGRESS, "---- Brush_LoadEntity ----\n");
|
||||
auto stats = Brush_LoadEntity(entity, hullnum);
|
||||
|
||||
entity->brushes = ChopBrushes(entity->brushes);
|
||||
|
||||
// we're discarding the brush
|
||||
if (discarded_trigger) {
|
||||
entity->brushes.clear();
|
||||
|
|
|
|||
|
|
@ -616,7 +616,7 @@ unchanged
|
|||
https://github.com/id-Software/Quake-2-Tools/blob/master/bsp/qbsp3/brushbsp.c#L935
|
||||
================
|
||||
*/
|
||||
static twosided<std::optional<brush_t>> SplitBrush(const brush_t &brush, const qplane3d &split)
|
||||
twosided<std::optional<brush_t>> SplitBrush(const brush_t &brush, const qplane3d &split)
|
||||
{
|
||||
twosided<std::optional<brush_t>> result;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue