clip_back/clip_front to match ChopWindingInPlace
simplify constructors for winding heap use std::vector again for mapentity_t since it's being copied because of the std::list
This commit is contained in:
parent
8b7a1c21c9
commit
426668701e
|
|
@ -244,10 +244,8 @@ void RemoveRedundantPlanes(std::vector<T> &planes)
|
|||
|
||||
// get flipped plane
|
||||
// frees winding.
|
||||
auto clipped = winding->clip(-plane2);
|
||||
|
||||
// discard the back, continue clipping the front part
|
||||
winding = clipped[0];
|
||||
winding = winding->clip_front(-plane2);
|
||||
|
||||
// check if everything was clipped away
|
||||
if (!winding)
|
||||
|
|
@ -607,9 +605,7 @@ static decomp_brush_t BuildInitialBrush_Q2(
|
|||
break;
|
||||
|
||||
// FIXME: epsilon is a lot larger than what qbsp uses
|
||||
auto [front, back] = winding->clip(plane2, DEFAULT_ON_EPSILON, true);
|
||||
|
||||
winding = back;
|
||||
winding = winding->clip_back(plane2, DEFAULT_ON_EPSILON, true);
|
||||
}
|
||||
|
||||
if (!winding)
|
||||
|
|
|
|||
|
|
@ -39,10 +39,10 @@ public:
|
|||
constexpr bitflags(const Enum &enumValue) : _bits(static_cast<type>(enumValue)) { }
|
||||
|
||||
constexpr bitflags(const bitflags ©) = default;
|
||||
constexpr bitflags(bitflags &&move) = default;
|
||||
constexpr bitflags(bitflags &&move) noexcept = default;
|
||||
|
||||
constexpr bitflags &operator=(const bitflags ©) = default;
|
||||
constexpr bitflags &operator=(bitflags &&move) = default;
|
||||
constexpr bitflags &operator=(bitflags &&move) noexcept = default;
|
||||
|
||||
inline explicit operator bool() const { return _bits.any(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -218,16 +218,14 @@ public:
|
|||
// construct winding from range.
|
||||
// iterators must have operator+ and operator-.
|
||||
template<typename Iter, std::enable_if_t<is_iterator_v<Iter>, int> = 0>
|
||||
inline winding_storage_heap_t(Iter begin, Iter end) : winding_storage_heap_t(end - begin)
|
||||
inline winding_storage_heap_t(Iter begin, Iter end) : values(begin, end)
|
||||
{
|
||||
std::copy_n(begin, size(), values.data());
|
||||
}
|
||||
|
||||
// copy constructor; uses optimized method of copying
|
||||
// data over.
|
||||
inline winding_storage_heap_t(const winding_storage_heap_t ©) : winding_storage_heap_t(copy.size())
|
||||
inline winding_storage_heap_t(const winding_storage_heap_t ©) : values(copy.values)
|
||||
{
|
||||
std::copy_n(copy.values.data(), copy.size(), values.data());
|
||||
}
|
||||
|
||||
// move constructor
|
||||
|
|
@ -259,21 +257,11 @@ public:
|
|||
|
||||
inline qvec3d &at(const size_t &index)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (index >= count)
|
||||
throw std::invalid_argument("index");
|
||||
#endif
|
||||
|
||||
return values[index];
|
||||
}
|
||||
|
||||
inline const qvec3d &at(const size_t &index) const
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (index >= count)
|
||||
throw std::invalid_argument("index");
|
||||
#endif
|
||||
|
||||
return values[index];
|
||||
}
|
||||
|
||||
|
|
@ -1050,12 +1038,138 @@ public:
|
|||
results[SIDE_BACK].push_back(mid);
|
||||
}
|
||||
|
||||
if (results[SIDE_FRONT].size() > MAX_POINTS_ON_WINDING || results[SIDE_BACK].size() > MAX_POINTS_ON_WINDING)
|
||||
FError("MAX_POINTS_ON_WINDING");
|
||||
|
||||
return {std::move(results[SIDE_FRONT]), std::move(results[SIDE_BACK])};
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
clip_front
|
||||
|
||||
The same as the above, except it will avoid allocating the front
|
||||
if it doesn't need to be modified; destroys *this if it does end up
|
||||
allocating a new winding.
|
||||
|
||||
Cheaper than clip(...)[SIDE_FRONT]
|
||||
==================
|
||||
*/
|
||||
std::optional<winding_base_t> clip_front(
|
||||
const qplane3d &plane, const vec_t &on_epsilon = DEFAULT_ON_EPSILON, const bool &keepon = false)
|
||||
{
|
||||
vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (size() + 1));
|
||||
planeside_t *sides = (planeside_t *)alloca(sizeof(planeside_t) * (size() + 1));
|
||||
|
||||
std::array<size_t, SIDE_TOTAL> counts = calc_sides(plane, dists, sides, on_epsilon);
|
||||
|
||||
if (keepon && !counts[SIDE_FRONT] && !counts[SIDE_BACK])
|
||||
return std::move(*this);
|
||||
|
||||
if (!counts[SIDE_FRONT])
|
||||
return std::nullopt;
|
||||
else if (!counts[SIDE_BACK])
|
||||
return std::move(*this);
|
||||
|
||||
winding_base_t result;
|
||||
result.reserve(size() + 4);
|
||||
|
||||
for (size_t i = 0; i < size(); i++) {
|
||||
const qvec3d &p1 = at(i);
|
||||
|
||||
if (sides[i] == SIDE_ON) {
|
||||
result.push_back(p1);
|
||||
continue;
|
||||
} else if (sides[i] == SIDE_FRONT) {
|
||||
result.push_back(p1);
|
||||
}
|
||||
|
||||
if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
|
||||
continue;
|
||||
|
||||
/* generate a split point */
|
||||
const qvec3d &p2 = at((i + 1) % size());
|
||||
|
||||
vec_t dot = dists[i] / (dists[i] - dists[i + 1]);
|
||||
qvec3d mid;
|
||||
|
||||
for (size_t j = 0; j < 3; j++) { /* avoid round off error when possible */
|
||||
if (plane.normal[j] == 1)
|
||||
mid[j] = plane.dist;
|
||||
else if (plane.normal[j] == -1)
|
||||
mid[j] = -plane.dist;
|
||||
else
|
||||
mid[j] = p1[j] + dot * (p2[j] - p1[j]);
|
||||
}
|
||||
|
||||
result.push_back(mid);
|
||||
}
|
||||
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
clip_back
|
||||
|
||||
The same as the above, except it will avoid allocating the front
|
||||
if it doesn't need to be modified; destroys *this if it does end up
|
||||
allocating a new winding.
|
||||
|
||||
Cheaper than clip(...)[SIDE_BACK]
|
||||
==================
|
||||
*/
|
||||
std::optional<winding_base_t> clip_back(
|
||||
const qplane3d &plane, const vec_t &on_epsilon = DEFAULT_ON_EPSILON, const bool &keepon = false) const
|
||||
{
|
||||
vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (size() + 1));
|
||||
planeside_t *sides = (planeside_t *)alloca(sizeof(planeside_t) * (size() + 1));
|
||||
|
||||
std::array<size_t, SIDE_TOTAL> counts = calc_sides(plane, dists, sides, on_epsilon);
|
||||
|
||||
if (keepon && !counts[SIDE_FRONT] && !counts[SIDE_BACK])
|
||||
return std::nullopt;
|
||||
|
||||
if (!counts[SIDE_FRONT])
|
||||
return std::move(*this);
|
||||
else if (!counts[SIDE_BACK])
|
||||
return std::nullopt;
|
||||
|
||||
winding_base_t result;
|
||||
result.reserve(size() + 4);
|
||||
|
||||
for (size_t i = 0; i < size(); i++) {
|
||||
const qvec3d &p1 = at(i);
|
||||
|
||||
if (sides[i] == SIDE_ON) {
|
||||
result.push_back(p1);
|
||||
continue;
|
||||
} else if (sides[i] == SIDE_BACK) {
|
||||
result.push_back(p1);
|
||||
}
|
||||
|
||||
if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
|
||||
continue;
|
||||
|
||||
/* generate a split point */
|
||||
const qvec3d &p2 = at((i + 1) % size());
|
||||
|
||||
vec_t dot = dists[i] / (dists[i] - dists[i + 1]);
|
||||
qvec3d mid;
|
||||
|
||||
for (size_t j = 0; j < 3; j++) { /* avoid round off error when possible */
|
||||
if (plane.normal[j] == 1)
|
||||
mid[j] = plane.dist;
|
||||
else if (plane.normal[j] == -1)
|
||||
mid[j] = -plane.dist;
|
||||
else
|
||||
mid[j] = p1[j] + dot * (p2[j] - p1[j]);
|
||||
}
|
||||
|
||||
result.push_back(mid);
|
||||
}
|
||||
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
void dice(vec_t subdiv, std::function<void(winding_base_t &)> save_fn)
|
||||
{
|
||||
if (!size())
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ public:
|
|||
qvec3d origin{};
|
||||
rotation_t rotation;
|
||||
|
||||
std::list<mapbrush_t> mapbrushes;
|
||||
std::vector<mapbrush_t> mapbrushes;
|
||||
|
||||
size_t numboxbevels = 0;
|
||||
size_t numedgebevels = 0;
|
||||
|
|
|
|||
|
|
@ -399,11 +399,9 @@ static void Leaf_MakeFaces(
|
|||
for (const qplane3d &plane2 : planes) {
|
||||
if (&plane2 == &plane)
|
||||
continue;
|
||||
|
||||
auto clipped = winding->clip(plane2);
|
||||
|
||||
|
||||
// discard the back, continue clipping the front part
|
||||
winding = clipped[0];
|
||||
winding = winding->clip_front(plane2);
|
||||
|
||||
// check if everything was clipped away
|
||||
if (!winding)
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ bool CreateBrushWindings(bspbrush_t *brush)
|
|||
if (brush->sides[j].bevel)
|
||||
continue;
|
||||
const qplane3d &plane = map.planes[brush->sides[j].planenum ^ 1];
|
||||
w = w->clip(plane, qbsp_options.epsilon.value(), false)[SIDE_FRONT]; // CLIP_EPSILON);
|
||||
w = w->clip_front(plane, qbsp_options.epsilon.value(), false); // CLIP_EPSILON);
|
||||
}
|
||||
|
||||
if (w) {
|
||||
|
|
|
|||
|
|
@ -2227,7 +2227,7 @@ inline void CalculateBrushBounds(mapbrush_t &ob)
|
|||
continue;
|
||||
}
|
||||
const auto &plane = map.get_plane(ob.faces[j].planenum ^ 1);
|
||||
w = w->clip(plane, 0)[SIDE_FRONT]; //CLIP_EPSILON);
|
||||
w = w->clip_front(plane, 0); //CLIP_EPSILON);
|
||||
}
|
||||
|
||||
if (w) {
|
||||
|
|
@ -2288,6 +2288,8 @@ void ProcessMapBrushes()
|
|||
}
|
||||
|
||||
num_removed++;
|
||||
// this is kinda slow but since most origin brushes are in
|
||||
// small brush models this won't matter much in practice
|
||||
it = entity.mapbrushes.erase(it);
|
||||
entity.rotation = rotation_t::origin_brush;
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -168,10 +168,17 @@ std::list<std::unique_ptr<buildportal_t>> MakeHeadnodePortals(tree_t *tree)
|
|||
|
||||
// clip the basewindings by all the other planes
|
||||
for (i = 0; i < 6; i++) {
|
||||
winding_t &w = *portals[i]->winding.get();
|
||||
|
||||
for (j = 0; j < 6; j++) {
|
||||
if (j == i)
|
||||
continue;
|
||||
portals[i]->winding = std::make_unique<winding_t>(*portals[i]->winding->clip(bplanes[j], qbsp_options.epsilon.value(), true)[SIDE_FRONT]);
|
||||
|
||||
if (auto w2 = w.clip_front(bplanes[j], qbsp_options.epsilon.value(), true)) {
|
||||
w = std::move(*w2);
|
||||
} else {
|
||||
FError("portal winding clipped away");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -201,9 +208,12 @@ static std::optional<winding_t> BaseWindingForNode(const node_t *node)
|
|||
|
||||
// clip by all the parents
|
||||
for (auto *np = node->parent; np && w;) {
|
||||
const planeside_t keep = (np->children[0].get() == node) ? SIDE_FRONT : SIDE_BACK;
|
||||
|
||||
w = w->clip(np->get_plane(), BASE_WINDING_EPSILON, false)[keep];
|
||||
if (np->children[0].get() == node) {
|
||||
w = w->clip_front(np->get_plane(), BASE_WINDING_EPSILON, false);
|
||||
} else {
|
||||
w = w->clip_back(np->get_plane(), BASE_WINDING_EPSILON, false);
|
||||
}
|
||||
|
||||
node = np;
|
||||
np = np->parent;
|
||||
|
|
@ -240,7 +250,8 @@ std::unique_ptr<buildportal_t> MakeNodePortal(node_t *node, const std::list<std:
|
|||
Error("CutNodePortals_r: mislinked portal");
|
||||
}
|
||||
|
||||
w = w->clip(plane, 0.1, false)[SIDE_FRONT];
|
||||
// fixme-brushbsp: magic number
|
||||
w = w->clip_front(plane, 0.1, false);
|
||||
}
|
||||
|
||||
if (!w) {
|
||||
|
|
|
|||
|
|
@ -651,7 +651,7 @@ hull sizes
|
|||
*/
|
||||
|
||||
static void BSPX_Brushes_AddModel(
|
||||
struct bspxbrushes_s *ctx, int modelnum, const std::list<mapbrush_t> &brushes)
|
||||
struct bspxbrushes_s *ctx, int modelnum, const std::vector<mapbrush_t> &brushes)
|
||||
{
|
||||
bspxbrushes_permodel permodel{1, modelnum};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue