diff --git a/include/qbsp/brush.hh b/include/qbsp/brush.hh index 756f038c..31ab0930 100644 --- a/include/qbsp/brush.hh +++ b/include/qbsp/brush.hh @@ -41,7 +41,7 @@ int Brush_ListCountWithCFlags(const brush_t *brush, int cflags); int Brush_ListCount(const brush_t *brush); int Brush_NumFaces(const brush_t *brush); -brush_t *LoadBrush(const mapbrush_t *mapbrush, int contents, const vec3_t rotate_offset, const int hullnum); +brush_t *LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, int contents, const vec3_t rotate_offset, const int hullnum); void FreeBrushes(mapentity_t *ent); int FindPlane(const vec3_t normal, const vec_t dist, int *side); diff --git a/man/qbsp.1 b/man/qbsp.1 index 6715e458..f20d52f5 100644 --- a/man/qbsp.1 +++ b/man/qbsp.1 @@ -256,6 +256,12 @@ Generates an LMSHIFT bspx lump for use by a light util. Note that both scaled an .IP "\fB""_mirrorinside"" ""n""\fP" Set to 1 to save mirrored inside faces for bmodels, so when the player view is inside the bmodel, they will still see the faces. (e.g. for func_water, or func_illusionary) +.IP "\fB""_no_bbox_rotation_expansion"" ""n""\fP" +By default, when using Hipnotic rotation or adding an "origin" brush to an entity, qbsp will expand the model bounding box to account for all possible rotations. +This is done because Quake doesn't take into account the model rotation when vis culling, so it needs to be done in qbsp to avoid incorrect culling. (see: https://github.com/id-Software/Quake/blob/master/WinQuake/world.c#L387 ). + +This behaviour can be opted out of by setting this key to 1. + .SH "OTHER SPECIAL-PURPOSE ENTITIES" .SS "func_illusionary_visblocker" diff --git a/qbsp/brush.cc b/qbsp/brush.cc index bc61beb1..7d1b1018 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -363,7 +363,7 @@ CreateBrushFaces ================= */ static face_t * -CreateBrushFaces(hullbrush_t *hullbrush, const vec3_t rotate_offset, +CreateBrushFaces(const mapentity_t *src, hullbrush_t *hullbrush, const vec3_t rotate_offset, const int hullnum) { int i, j, k; @@ -472,7 +472,10 @@ CreateBrushFaces(hullbrush_t *hullbrush, const vec3_t rotate_offset, // Rotatable objects must have a bounding box big enough to // account for all its rotations - if (0 /*rotate_offset[0] || rotate_offset[1] || rotate_offset[2]*/) { + const bool noExpand = static_cast( + atoi(ValueForKey(src, "_no_bbox_rotation_expansion")) + ); + if ((rotate_offset[0] || rotate_offset[1] || rotate_offset[2]) && !noExpand) { vec_t delta; delta = fabs(max); @@ -858,7 +861,7 @@ LoadBrush Converts a mapbrush to a bsp brush =============== */ -brush_t *LoadBrush(const mapbrush_t *mapbrush, int contents, const vec3_t rotate_offset, const int hullnum) +brush_t *LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, int contents, const vec3_t rotate_offset, const int hullnum) { hullbrush_t hullbrush; brush_t *brush; @@ -878,11 +881,11 @@ brush_t *LoadBrush(const mapbrush_t *mapbrush, int contents, const vec3_t rotate hullbrush.faces[i] = mapbrush->face(i); if (hullnum == 0) { - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } else { // for clipping hulls, don't apply rotation offset yet.. // it will be applied below - facelist = CreateBrushFaces(&hullbrush, vec3_origin, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, vec3_origin, hullnum); } if (!facelist) { @@ -897,19 +900,19 @@ brush_t *LoadBrush(const mapbrush_t *mapbrush, int contents, const vec3_t rotate vec3_t size[2] = { {-16, -16, -36}, {16, 16, 36} }; ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } else if (hullnum == 2) { vec3_t size[2] = { {-32, -32, -32}, {32, 32, 32} }; ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } else if (hullnum == 3) { vec3_t size[2] = { {-16, -16, -18}, {16, 16, 18} }; ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } } else if (options.hexen2) @@ -918,19 +921,19 @@ brush_t *LoadBrush(const mapbrush_t *mapbrush, int contents, const vec3_t rotate vec3_t size[2] = { {-16, -16, -32}, {16, 16, 24} }; ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } else if (hullnum == 2) { vec3_t size[2] = { {-24, -24, -20}, {24, 24, 20} }; ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } else if (hullnum == 3) { vec3_t size[2] = { {-16, -16, -12}, {16, 16, 16} }; ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } else if (hullnum == 4) { #if 0 @@ -938,21 +941,21 @@ brush_t *LoadBrush(const mapbrush_t *mapbrush, int contents, const vec3_t rotate vec3_t size[2] = { {-40, -40, -42}, {40, 40, 42} }; ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } else #endif { /*mission pack*/ vec3_t size[2] = { {-8, -8, -8}, {8, 8, 8} }; ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } } else if (hullnum == 5) { vec3_t size[2] = { {-48, -48, -50}, {48, 48, 50} }; ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } } else @@ -962,13 +965,13 @@ brush_t *LoadBrush(const mapbrush_t *mapbrush, int contents, const vec3_t rotate ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } else if (hullnum == 2) { vec3_t size[2] = { {-32, -32, -64}, {32, 32, 24} }; ExpandBrush(&hullbrush, size, facelist); FreeBrushFaces(facelist); - facelist = CreateBrushFaces(&hullbrush, rotate_offset, hullnum); + facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum); } } @@ -1112,7 +1115,7 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum) continue; } - brush_t *brush = LoadBrush(mapbrush, contents, vec3_origin, 0); + brush_t *brush = LoadBrush(src, mapbrush, contents, vec3_origin, 0); if (brush) { vec3_t origin; VectorAdd(brush->mins, brush->maxs, origin); @@ -1237,7 +1240,7 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum) */ if (contents == CONTENTS_CLIP) { if (hullnum == 0) { - brush_t *brush = LoadBrush(mapbrush, contents, rotate_offset, hullnum); + brush_t *brush = LoadBrush(src, mapbrush, contents, rotate_offset, hullnum); if (brush) { AddToBounds(dst, brush->mins); AddToBounds(dst, brush->maxs); @@ -1283,7 +1286,7 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum) if (hullnum > 0 && contents == CONTENTS_SKY) contents = CONTENTS_SOLID; - brush_t *brush = LoadBrush(mapbrush, contents, rotate_offset, hullnum); + brush_t *brush = LoadBrush(src, mapbrush, contents, rotate_offset, hullnum); if (!brush) continue; diff --git a/qbsp/map.cc b/qbsp/map.cc index 39511d8e..bd996526 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -2353,7 +2353,7 @@ TestExpandBrushes(const mapentity_t *src) for (int i = 0; i < src->nummapbrushes; i++) { const mapbrush_t *mapbrush = &src->mapbrush(i); - brush_t *hull1brush = LoadBrush(mapbrush, CONTENTS_SOLID, vec3_origin, 1); + brush_t *hull1brush = LoadBrush(src, mapbrush, CONTENTS_SOLID, vec3_origin, 1); if (hull1brush != nullptr) hull1brushes.push_back(hull1brush); diff --git a/qbsp/test_qbsp.cc b/qbsp/test_qbsp.cc index 2eef6fc4..e1594b98 100644 --- a/qbsp/test_qbsp.cc +++ b/qbsp/test_qbsp.cc @@ -115,7 +115,7 @@ TEST(qbsp, duplicatePlanes) { EXPECT_EQ(0, worldspawn.numbrushes); EXPECT_EQ(6, worldspawn.mapbrush(0).numfaces); - brush_t *brush = LoadBrush(&worldspawn.mapbrush(0), CONTENTS_SOLID, vec3_origin, 0); + brush_t *brush = LoadBrush(&worldspawn, &worldspawn.mapbrush(0), CONTENTS_SOLID, vec3_origin, 0); ASSERT_NE(nullptr, brush); EXPECT_EQ(6, Brush_NumFaces(brush)); FreeBrush(brush); @@ -141,7 +141,7 @@ static brush_t *load128x128x32Brush() mapentity_t worldspawn = LoadMap(map); Q_assert(1 == worldspawn.nummapbrushes); - brush_t *brush = LoadBrush(&worldspawn.mapbrush(0), CONTENTS_SOLID, vec3_origin, 0); + brush_t *brush = LoadBrush(&worldspawn, &worldspawn.mapbrush(0), CONTENTS_SOLID, vec3_origin, 0); Q_assert(nullptr != brush); brush->contents = CONTENTS_SOLID;