allow update_bounds to tell the caller that a brush may have been destroyed

This commit is contained in:
Jonathan 2022-08-08 15:50:23 -04:00
parent 712dd24cff
commit b3fbf8841d
5 changed files with 45 additions and 21 deletions

View File

@ -73,12 +73,12 @@ struct bspbrush_t
qvec3d sphere_origin;
double sphere_radius;
void update_bounds();
bool update_bounds();
std::unique_ptr<bspbrush_t> copy_unique() const;
};
using bspbrush_vector_t = std::vector<std::unique_ptr<bspbrush_t>>;
bspbrush_t LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents, const int hullnum);
void CreateBrushWindings(bspbrush_t *brush);
std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents, const int hullnum);
bool CreateBrushWindings(bspbrush_t *brush);

View File

@ -214,7 +214,7 @@ Create all of the windings for the specified brush, and
calculate its bounds.
==================
*/
void CreateBrushWindings(bspbrush_t *brush)
bool CreateBrushWindings(bspbrush_t *brush)
{
std::optional<winding_t> w;
@ -231,13 +231,22 @@ void CreateBrushWindings(bspbrush_t *brush)
}
if (w) {
for (auto &p : *w) {
for (auto &v : p) {
if (fabs(v) > qbsp_options.worldextent.value()) {
logging::print("WARNING: {}: invalid winding point\n", brush->mapbrush ? brush->mapbrush->line : parser_source_location{});
w = std::nullopt;
}
}
}
side->w = *w;
} else {
side->w.clear();
}
}
brush->update_bounds();
return brush->update_bounds();
}
/*
@ -247,7 +256,7 @@ LoadBrush
Converts a mapbrush to a bsp brush
===============
*/
bspbrush_t LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents,
std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents,
const int hullnum)
{
// create the brush
@ -297,7 +306,9 @@ bspbrush_t LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const c
}
}
CreateBrushWindings(&brush);
if (!CreateBrushWindings(&brush)) {
return std::nullopt;
}
for (auto &face : brush.sides) {
CheckFace(&face, *face.source);
@ -451,8 +462,9 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int
*/
if (hullnum != HULL_COLLISION && contents.is_clip(qbsp_options.target_game)) {
if (hullnum == 0) {
bspbrush_t brush = LoadBrush(src, &mapbrush, contents, hullnum);
dst->bounds += brush.bounds;
if (auto brush = LoadBrush(src, &mapbrush, contents, hullnum)) {
dst->bounds += brush->bounds;
}
continue;
// for hull1, 2, etc., convert clip to CONTENTS_SOLID
} else {
@ -497,22 +509,26 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int
contents.set_clips_same_type(clipsametype);
contents.illusionary_visblocker = func_illusionary_visblocker;
bspbrush_t brush = LoadBrush(src, &mapbrush, contents, hullnum);
auto brush = LoadBrush(src, &mapbrush, contents, hullnum);
brush.lmshift = lmshift;
if (!brush) {
continue;
}
for (auto &face : brush.sides) {
brush->lmshift = lmshift;
for (auto &face : brush->sides) {
face.lmshift = lmshift;
}
if (classname == std::string_view("func_areaportal")) {
brush.func_areaportal = const_cast<mapentity_t *>(src); // FIXME: get rid of consts on src in the callers?
brush->func_areaportal = const_cast<mapentity_t *>(src); // FIXME: get rid of consts on src in the callers?
}
qbsp_options.target_game->count_contents_in_stats(brush.contents, stats);
qbsp_options.target_game->count_contents_in_stats(brush->contents, stats);
dst->bounds += brush.bounds;
brushes.push_back(std::make_unique<bspbrush_t>(std::move(brush)));
dst->bounds += brush->bounds;
brushes.push_back(std::make_unique<bspbrush_t>(std::move(*brush)));
}
logging::percent(src->mapbrushes.size(), src->mapbrushes.size(), src == map.world_entity());
@ -562,9 +578,10 @@ void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_vector_t
qbsp_options.target_game->print_content_stats(*stats, "brushes");
}
void bspbrush_t::update_bounds()
bool bspbrush_t::update_bounds()
{
this->bounds = {};
for (const auto &face : sides) {
if (face.w) {
this->bounds = this->bounds.unionWith(face.w.bounds());
@ -575,12 +592,16 @@ void bspbrush_t::update_bounds()
// todo: map_source_location in bspbrush_t
if (this->bounds.mins()[0] <= -qbsp_options.worldextent.value() || this->bounds.maxs()[0] >= qbsp_options.worldextent.value()) {
logging::print("WARNING: {}: brush bounds out of range\n", mapbrush ? mapbrush->line : parser_source_location());
return false;
}
if (this->bounds.mins()[0] >= qbsp_options.worldextent.value() || this->bounds.maxs()[0] <= -qbsp_options.worldextent.value()) {
logging::print("WARNING: {}: no visible sides on brush\n", mapbrush ? mapbrush->line : parser_source_location());
return false;
}
}
this->sphere_origin = (bounds.mins() + bounds.maxs()) / 2.0;
this->sphere_radius = qv::length((bounds.maxs() - bounds.mins()) / 2.0);
return true;
}

View File

@ -1040,6 +1040,7 @@ static std::unique_ptr<tree_t> BrushBSP_internal(mapentity_t *entity, std::vecto
size_t c_faces = 0;
size_t c_nonvisfaces = 0;
size_t c_brushes = 0;
for (const auto &b : brushlist) {
c_brushes++;

View File

@ -2824,10 +2824,12 @@ static void TestExpandBrushes(const mapentity_t *src)
std::vector<std::unique_ptr<bspbrush_t>> hull1brushes;
for (auto &mapbrush : src->mapbrushes) {
bspbrush_t hull1brush = LoadBrush(src, &mapbrush, {CONTENTS_SOLID},
auto hull1brush = LoadBrush(src, &mapbrush, {CONTENTS_SOLID},
qbsp_options.target_game->id == GAME_QUAKE_II ? HULL_COLLISION : 1);
hull1brushes.emplace_back(std::make_unique<bspbrush_t>(std::move(hull1brush)));
if (hull1brush) {
hull1brushes.emplace_back(std::make_unique<bspbrush_t>(std::move(*hull1brush)));
}
}
WriteBspBrushMap("expanded.map", hull1brushes);

View File

@ -401,8 +401,8 @@ TEST_CASE("duplicatePlanes", "[qbsp]")
REQUIRE(1 == worldspawn.mapbrushes.size());
CHECK(6 == worldspawn.mapbrushes.front().faces.size());
bspbrush_t brush = LoadBrush(&worldspawn, &worldspawn.mapbrushes.front(), {CONTENTS_SOLID}, 0);
CHECK(6 == brush.sides.size());
auto brush = LoadBrush(&worldspawn, &worldspawn.mapbrushes.front(), {CONTENTS_SOLID}, 0);
CHECK(6 == brush->sides.size());
}
/**