move in the rest of the missing code back into LoadBrush
fix bug with c_brushesremoved brushes move & CreateBrushWindings use where required store the source face we made a bspbrush_t side from fix test issue
This commit is contained in:
parent
5da88122a5
commit
ec62a0e8d0
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
class mapentity_t;
|
||||
struct maptexinfo_t;
|
||||
struct mapface_t;
|
||||
|
||||
struct side_t
|
||||
{
|
||||
|
|
@ -43,6 +44,7 @@ struct side_t
|
|||
// non-visible means we can discard the brush side
|
||||
// (avoiding generating a BSP spit, so expanding it outwards)
|
||||
bool bevel; // don't ever use for bsp splitting
|
||||
const mapface_t *source; // the mapface we were generated from
|
||||
|
||||
bool tested;
|
||||
|
||||
|
|
@ -82,14 +84,7 @@ struct bspbrush_t
|
|||
qplane3d Face_Plane(const face_t *face);
|
||||
qplane3d Face_Plane(const side_t *face);
|
||||
|
||||
enum class rotation_t
|
||||
{
|
||||
none,
|
||||
hipnotic,
|
||||
origin_brush
|
||||
};
|
||||
|
||||
std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents,
|
||||
const int hullnum);
|
||||
bspbrush_t LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents, const int hullnum);
|
||||
contentflags_t Brush_GetContents(const mapbrush_t *mapbrush);
|
||||
void CreateBrushWindings(bspbrush_t *brush);
|
||||
void FreeBrushes(mapentity_t *ent);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ struct mapface_t
|
|||
int texinfo = 0;
|
||||
int linenum = 0;
|
||||
bool bevel = false;
|
||||
winding_t winding; // winding used to calculate bevels
|
||||
|
||||
surfflags_t flags{};
|
||||
|
||||
|
|
@ -55,8 +56,6 @@ struct mapface_t
|
|||
// for convert
|
||||
std::optional<extended_texinfo_t> raw_info;
|
||||
|
||||
winding_t winding;
|
||||
|
||||
bool set_planepts(const std::array<qvec3d, 3> &pts);
|
||||
|
||||
const texvecf &get_texvecs() const;
|
||||
|
|
@ -87,6 +86,13 @@ struct lumpdata
|
|||
void *data;
|
||||
};
|
||||
|
||||
enum class rotation_t
|
||||
{
|
||||
none,
|
||||
hipnotic,
|
||||
origin_brush
|
||||
};
|
||||
|
||||
class mapentity_t
|
||||
{
|
||||
public:
|
||||
|
|
@ -100,6 +106,7 @@ public:
|
|||
#endif
|
||||
|
||||
qvec3d origin{};
|
||||
rotation_t rotation;
|
||||
|
||||
std::list<mapbrush_t> mapbrushes;
|
||||
|
||||
|
|
|
|||
144
qbsp/brush.cc
144
qbsp/brush.cc
|
|
@ -321,6 +321,40 @@ contentflags_t Brush_GetContents(const mapbrush_t *mapbrush)
|
|||
return base_contents;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CreateBrushWindings
|
||||
|
||||
Create all of the windings for the specified brush, and
|
||||
calculate its bounds.
|
||||
==================
|
||||
*/
|
||||
void CreateBrushWindings(bspbrush_t *brush)
|
||||
{
|
||||
std::optional<winding_t> w;
|
||||
|
||||
for (int i = 0; i < brush->sides.size(); i++) {
|
||||
side_t *side = &brush->sides[i];
|
||||
w = BaseWindingForPlane(Face_Plane(side));
|
||||
for (int j = 0; j < brush->sides.size() && w; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
if (brush->sides[j].bevel)
|
||||
continue;
|
||||
qplane3d plane = -Face_Plane(&brush->sides[j]);
|
||||
w = w->clip(plane, 0, false)[SIDE_FRONT]; // CLIP_EPSILON);
|
||||
}
|
||||
|
||||
if (w) {
|
||||
side->w = *w;
|
||||
} else {
|
||||
side->w.clear();
|
||||
}
|
||||
}
|
||||
|
||||
brush->update_bounds();
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
LoadBrush
|
||||
|
|
@ -328,18 +362,20 @@ LoadBrush
|
|||
Converts a mapbrush to a bsp brush
|
||||
===============
|
||||
*/
|
||||
std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents,
|
||||
bspbrush_t LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents,
|
||||
const int hullnum)
|
||||
{
|
||||
// create the brush
|
||||
bspbrush_t brush{};
|
||||
brush.contents = contents;
|
||||
brush.sides.reserve(mapbrush->faces.size());
|
||||
brush.mapbrush = mapbrush;
|
||||
|
||||
for (size_t i = 0; i < mapbrush->faces.size(); i++) {
|
||||
auto &src = mapbrush->faces[i];
|
||||
|
||||
if (src.bevel) {
|
||||
// don't add bevels for the point hull
|
||||
if (hullnum <= 0 && src.bevel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -348,26 +384,73 @@ std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, const mapbrush_t *ma
|
|||
dst.texinfo = hullnum > 0 ? 0 : src.texinfo;
|
||||
dst.planenum = src.planenum;
|
||||
dst.bevel = src.bevel;
|
||||
|
||||
// TEMP
|
||||
dst.w = src.winding;
|
||||
|
||||
CheckFace(&dst, src);
|
||||
dst.source = &src;
|
||||
}
|
||||
|
||||
// todo: expand planes, recalculate bounds & windings
|
||||
brush.bounds = mapbrush->bounds;
|
||||
|
||||
#if 0
|
||||
// expand the brushes for the hull
|
||||
if (hullnum > 0) {
|
||||
auto &hulls = qbsp_options.target_game->get_hull_sizes();
|
||||
Q_assert(hullnum < hulls.size());
|
||||
ExpandBrush(&hullbrush, *(hulls.begin() + hullnum), facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, hullnum);
|
||||
}
|
||||
#endif
|
||||
auto &hull = *(hulls.begin() + hullnum);
|
||||
|
||||
for (auto &mapface : brush.sides) {
|
||||
if (mapface.get_texinfo().flags.no_expand) {
|
||||
continue;
|
||||
}
|
||||
qvec3d corner{};
|
||||
for (int32_t x = 0; x < 3; x++) {
|
||||
if (mapface.get_plane().get_normal()[x] > 0) {
|
||||
corner[x] = hull[1][x];
|
||||
} else if (mapface.get_plane().get_normal()[x] < 0) {
|
||||
corner[x] = hull[0][x];
|
||||
}
|
||||
}
|
||||
qplane3d plane = mapface.get_plane();
|
||||
plane.dist += qv::dot(corner, plane.normal);
|
||||
mapface.planenum = map.add_or_find_plane(plane);
|
||||
mapface.bevel = false;
|
||||
}
|
||||
}
|
||||
|
||||
CreateBrushWindings(&brush);
|
||||
|
||||
for (auto &face : brush.sides) {
|
||||
CheckFace(&face, *face.source);
|
||||
}
|
||||
|
||||
// Rotatable objects must have a bounding box big enough to
|
||||
// account for all its rotations
|
||||
|
||||
// if -wrbrushes is in use, don't do this for the clipping hulls because it depends on having
|
||||
// the actual non-hacked bbox (it doesn't write axial planes).
|
||||
|
||||
// Hexen2 also doesn't want the bbox expansion, it's handled in engine (see: SV_LinkEdict)
|
||||
|
||||
// Only do this for hipnotic rotation. For origin brushes in Quake, it breaks some of their
|
||||
// uses (e.g. func_train). This means it's up to the mapper to expand the model bounds with
|
||||
// clip brushes if they're going to rotate a model in vanilla Quake and not use hipnotic rotation.
|
||||
// The idea behind the bounds expansion was to avoid incorrect vis culling (AFAIK).
|
||||
const bool shouldExpand = (src->origin[0] != 0.0 || src->origin[1] != 0.0 || src->origin[2] != 0.0) &&
|
||||
src->rotation == rotation_t::hipnotic &&
|
||||
(hullnum >= 0) // hullnum < 0 corresponds to -wrbrushes clipping hulls
|
||||
&& qbsp_options.target_game->id != GAME_HEXEN_II; // never do this in Hexen 2
|
||||
|
||||
if (shouldExpand) {
|
||||
vec_t max = -std::numeric_limits<vec_t>::infinity(), min = std::numeric_limits<vec_t>::infinity();
|
||||
|
||||
for (auto &v : brush.bounds.mins()) {
|
||||
min = ::min(min, v);
|
||||
max = ::max(max, v);
|
||||
}
|
||||
for (auto &v : brush.bounds.maxs()) {
|
||||
min = ::min(min, v);
|
||||
max = ::max(max, v);
|
||||
}
|
||||
|
||||
vec_t delta = std::max(fabs(max), fabs(min));
|
||||
brush.bounds = {-delta, delta};
|
||||
}
|
||||
|
||||
brush.mapbrush = mapbrush;
|
||||
return brush;
|
||||
}
|
||||
|
||||
|
|
@ -483,12 +566,8 @@ 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) {
|
||||
std::optional<bspbrush_t> brush = LoadBrush(src, &mapbrush, contents, hullnum);
|
||||
|
||||
if (brush) {
|
||||
dst->bounds += brush->bounds;
|
||||
}
|
||||
|
||||
bspbrush_t brush = LoadBrush(src, &mapbrush, contents, hullnum);
|
||||
dst->bounds += brush.bounds;
|
||||
continue;
|
||||
// for hull1, 2, etc., convert clip to CONTENTS_SOLID
|
||||
} else {
|
||||
|
|
@ -533,22 +612,21 @@ 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;
|
||||
|
||||
std::optional<bspbrush_t> brush = LoadBrush(src, &mapbrush, contents, hullnum);
|
||||
if (!brush)
|
||||
continue;
|
||||
bspbrush_t brush = LoadBrush(src, &mapbrush, contents, hullnum);
|
||||
|
||||
brush->lmshift = lmshift;
|
||||
brush.lmshift = lmshift;
|
||||
|
||||
for (auto &face : brush->sides)
|
||||
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?
|
||||
}
|
||||
|
||||
qbsp_options.target_game->count_contents_in_stats(brush->contents, stats);
|
||||
dst->brushes.push_back(std::make_unique<bspbrush_t>(brush.value()));
|
||||
dst->bounds += brush->bounds;
|
||||
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?
|
||||
}
|
||||
|
||||
qbsp_options.target_game->count_contents_in_stats(brush.contents, stats);
|
||||
dst->brushes.push_back(std::make_unique<bspbrush_t>(std::move(brush)));
|
||||
dst->bounds += brush.bounds;
|
||||
}
|
||||
|
||||
logging::percent(src->mapbrushes.size(), src->mapbrushes.size(), src == map.world_entity());
|
||||
|
|
|
|||
|
|
@ -70,39 +70,6 @@ struct bspstats_t
|
|||
std::atomic<int> c_brushesonesided;
|
||||
};
|
||||
|
||||
/*
|
||||
==================
|
||||
CreateBrushWindings
|
||||
|
||||
Currently only used in BrushFromBounds
|
||||
==================
|
||||
*/
|
||||
static void CreateBrushWindings(bspbrush_t *brush)
|
||||
{
|
||||
std::optional<winding_t> w;
|
||||
|
||||
for (int i = 0; i < brush->sides.size(); i++) {
|
||||
side_t *side = &brush->sides[i];
|
||||
w = BaseWindingForPlane(Face_Plane(side));
|
||||
for (int j = 0; j < brush->sides.size() && w; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
if (brush->sides[j].bevel)
|
||||
continue;
|
||||
qplane3d plane = -Face_Plane(&brush->sides[j]);
|
||||
w = w->clip(plane, 0, false)[SIDE_FRONT]; // CLIP_EPSILON);
|
||||
}
|
||||
|
||||
if (w) {
|
||||
side->w = *w;
|
||||
} else {
|
||||
side->w.clear();
|
||||
}
|
||||
}
|
||||
|
||||
brush->update_bounds();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
BrushFromBounds
|
||||
|
|
@ -575,6 +542,8 @@ static twosided<std::unique_ptr<bspbrush_t>> SplitBrush(std::unique_ptr<bspbrush
|
|||
|
||||
if (!result[0] && !result[1]) {
|
||||
stats.c_brushesremoved++;
|
||||
|
||||
return result;
|
||||
} else if (!result[0] || !result[1]) {
|
||||
stats.c_brushesonesided++;
|
||||
|
||||
|
|
|
|||
44
qbsp/map.cc
44
qbsp/map.cc
|
|
@ -2215,7 +2215,7 @@ void ProcessMapBrushes()
|
|||
for (auto &entity : map.entities) {
|
||||
|
||||
/* Origin brush support */
|
||||
rotation_t rottype = rotation_t::none;
|
||||
entity.rotation = rotation_t::none;
|
||||
|
||||
for (auto it = entity.mapbrushes.begin(); it != entity.mapbrushes.end(); ) {
|
||||
auto &brush = *it;
|
||||
|
|
@ -2239,7 +2239,7 @@ void ProcessMapBrushes()
|
|||
|
||||
num_removed++;
|
||||
it = entity.mapbrushes.erase(it);
|
||||
rottype = rotation_t::origin_brush;
|
||||
entity.rotation = rotation_t::origin_brush;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -2256,17 +2256,16 @@ void ProcessMapBrushes()
|
|||
map.total_brushes += entity.mapbrushes.size();
|
||||
|
||||
/* Hipnotic rotation */
|
||||
if (rottype == rotation_t::none) {
|
||||
if (entity.rotation == rotation_t::none) {
|
||||
if (!Q_strncasecmp(entity.epairs.get("classname"), "rotate_", 7)) {
|
||||
entity.origin = FixRotateOrigin(&entity);
|
||||
rottype = rotation_t::hipnotic;
|
||||
entity.rotation = rotation_t::hipnotic;
|
||||
}
|
||||
}
|
||||
|
||||
// offset brush bounds
|
||||
if (rottype != rotation_t::none) {
|
||||
if (entity.rotation != rotation_t::none) {
|
||||
for (auto &brush : entity.mapbrushes) {
|
||||
brush.bounds = brush.bounds.translate(-entity.origin);
|
||||
|
||||
for (auto &f : brush.faces) {
|
||||
// account for texture offset, from txqbsp-xt
|
||||
|
|
@ -2285,35 +2284,12 @@ void ProcessMapBrushes()
|
|||
f.planenum = map.add_or_find_plane(plane);
|
||||
}
|
||||
|
||||
// re-calculate brush bounds
|
||||
// re-calculate brush bounds/windings
|
||||
CalculateBrushBounds(brush);
|
||||
|
||||
num_offset++;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
// Rotatable objects must have a bounding box big enough to
|
||||
// account for all its rotations
|
||||
|
||||
// if -wrbrushes is in use, don't do this for the clipping hulls because it depends on having
|
||||
// the actual non-hacked bbox (it doesn't write axial planes).
|
||||
|
||||
// Hexen2 also doesn't want the bbox expansion, it's handled in engine (see: SV_LinkEdict)
|
||||
|
||||
// Only do this for hipnotic rotation. For origin brushes in Quake, it breaks some of their
|
||||
// uses (e.g. func_train). This means it's up to the mapper to expand the model bounds with
|
||||
// clip brushes if they're going to rotate a model in vanilla Quake and not use hipnotic rotation.
|
||||
// The idea behind the bounds expansion was to avoid incorrect vis culling (AFAIK).
|
||||
const bool shouldExpand = (rotate_offset[0] != 0.0 || rotate_offset[1] != 0.0 || rotate_offset[2] != 0.0) &&
|
||||
rottype == rotation_t::hipnotic &&
|
||||
(hullnum >= 0) // hullnum < 0 corresponds to -wrbrushes clipping hulls
|
||||
&& qbsp_options.target_game->id != GAME_HEXEN_II; // never do this in Hexen 2
|
||||
|
||||
if (shouldExpand) {
|
||||
vec_t delta = std::max(fabs(max), fabs(min));
|
||||
hullbrush->bounds = {-delta, delta};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
logging::print(logging::flag::STAT, " {:8} brushes\n", map.total_brushes);
|
||||
|
|
@ -2715,6 +2691,8 @@ void CalculateWorldExtent(void)
|
|||
}
|
||||
|
||||
qbsp_options.worldextent.setValue((extents + hull_extents) * 2, settings::source::GAME_TARGET);
|
||||
|
||||
logging::print("INFO: world extents calculated to {} units\n", qbsp_options.worldextent.value());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2774,12 +2752,10 @@ static void TestExpandBrushes(const mapentity_t *src)
|
|||
std::vector<std::unique_ptr<bspbrush_t>> hull1brushes;
|
||||
|
||||
for (auto &mapbrush : src->mapbrushes) {
|
||||
std::optional<bspbrush_t> hull1brush = LoadBrush(src, &mapbrush, {CONTENTS_SOLID},
|
||||
bspbrush_t hull1brush = LoadBrush(src, &mapbrush, {CONTENTS_SOLID},
|
||||
qbsp_options.target_game->id == GAME_QUAKE_II ? HULL_COLLISION : 1);
|
||||
|
||||
if (hull1brush) {
|
||||
hull1brushes.emplace_back(std::make_unique<bspbrush_t>(std::move(*hull1brush)));
|
||||
}
|
||||
hull1brushes.emplace_back(std::make_unique<bspbrush_t>(std::move(hull1brush)));
|
||||
}
|
||||
|
||||
WriteBspBrushMap("expanded.map", hull1brushes);
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ static void MarkVisibleBrushSides_R(node_t *node)
|
|||
// leaf that are coplanar
|
||||
for (auto *brush : neighbour_leaf->original_brushes) {
|
||||
for (auto &side : brush->sides) {
|
||||
//if (qv::epsilonEqual(side.plane, portal->plane)) {
|
||||
// fixme-brushbsp: should this be get_plane() ?
|
||||
if (qv::epsilonEqual(side.get_positive_plane(), portal->plane)) {
|
||||
// we've found a brush side in an original brush in the neighbouring
|
||||
// leaf, on a portal to this (non-opaque) leaf, so mark it as visible.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ static mapentity_t LoadMap(const char *map)
|
|||
|
||||
parser_t parser(map);
|
||||
|
||||
// FIXME: ???
|
||||
mapentity_t &entity = ::map.entities.emplace_back();
|
||||
|
||||
mapentity_t worldspawn;
|
||||
|
||||
// FIXME: adds the brush to the global map...
|
||||
|
|
@ -399,10 +402,8 @@ TEST_CASE("duplicatePlanes", "[qbsp]")
|
|||
CHECK(0 == worldspawn.brushes.size());
|
||||
CHECK(6 == worldspawn.mapbrushes.front().faces.size());
|
||||
|
||||
std::optional<bspbrush_t> brush =
|
||||
LoadBrush(&worldspawn, &worldspawn.mapbrushes.front(), {CONTENTS_SOLID}, 0);
|
||||
REQUIRE(std::nullopt != brush);
|
||||
CHECK(6 == brush->sides.size());
|
||||
bspbrush_t brush = LoadBrush(&worldspawn, &worldspawn.mapbrushes.front(), {CONTENTS_SOLID}, 0);
|
||||
CHECK(6 == brush.sides.size());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue