qbsp: initial ChopBrushes implementation
This commit is contained in:
parent
019b8cb9ed
commit
cb2268efdf
|
|
@ -21,10 +21,13 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <qbsp/brush.hh>
|
||||||
|
|
||||||
#include <common/qvec.hh>
|
#include <common/qvec.hh>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
struct face_t;
|
struct face_t;
|
||||||
|
|
||||||
|
|
@ -33,3 +36,4 @@ face_t *NewFaceFromFace(const face_t *in);
|
||||||
face_t *MirrorFace(const face_t *face);
|
face_t *MirrorFace(const face_t *face);
|
||||||
std::tuple<face_t *, face_t *> SplitFace(face_t *in, const qplane3d &split);
|
std::tuple<face_t *, face_t *> SplitFace(face_t *in, const qplane3d &split);
|
||||||
void UpdateFaceSphere(face_t *in);
|
void UpdateFaceSphere(face_t *in);
|
||||||
|
std::vector<brush_t> ChopBrushes(const std::vector<brush_t> &input);
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,13 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <qbsp/brush.hh>
|
||||||
|
|
||||||
|
#include <common/qvec.hh>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
extern std::atomic<int> splitnodes;
|
extern std::atomic<int> splitnodes;
|
||||||
|
|
||||||
|
|
@ -32,4 +37,5 @@ class mapentity_t;
|
||||||
|
|
||||||
void DetailToSolid(node_t *node);
|
void DetailToSolid(node_t *node);
|
||||||
void PruneNodes(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);
|
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/brush.hh>
|
||||||
#include <qbsp/csg4.hh>
|
#include <qbsp/csg4.hh>
|
||||||
#include <qbsp/map.hh>
|
#include <qbsp/map.hh>
|
||||||
|
#include <qbsp/solidbsp.hh>
|
||||||
#include <qbsp/qbsp.hh>
|
#include <qbsp/qbsp.hh>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
@ -474,3 +475,126 @@ std::list<face_t *> CSGFace(face_t *srcface, const mapentity_t *srcentity, const
|
||||||
|
|
||||||
return result;
|
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 <common/settings.hh>
|
||||||
|
|
||||||
#include <qbsp/brush.hh>
|
#include <qbsp/brush.hh>
|
||||||
|
#include <qbsp/csg4.hh>
|
||||||
#include <qbsp/map.hh>
|
#include <qbsp/map.hh>
|
||||||
#include <qbsp/merge.hh>
|
#include <qbsp/merge.hh>
|
||||||
#include <qbsp/portals.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");
|
logging::print(logging::flag::PROGRESS, "---- Brush_LoadEntity ----\n");
|
||||||
auto stats = Brush_LoadEntity(entity, hullnum);
|
auto stats = Brush_LoadEntity(entity, hullnum);
|
||||||
|
|
||||||
|
entity->brushes = ChopBrushes(entity->brushes);
|
||||||
|
|
||||||
// we're discarding the brush
|
// we're discarding the brush
|
||||||
if (discarded_trigger) {
|
if (discarded_trigger) {
|
||||||
entity->brushes.clear();
|
entity->brushes.clear();
|
||||||
|
|
|
||||||
|
|
@ -616,7 +616,7 @@ unchanged
|
||||||
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::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;
|
twosided<std::optional<brush_t>> result;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue