qbsp: fix origin brushes in hexen 2. Drop _no_bbox_rotation_expansion
document origin brushes. Never expand the bbox when origin brushes are in use.
This commit is contained in:
parent
b56afb5988
commit
c30a0a46a9
|
|
@ -41,7 +41,11 @@ 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 mapentity_t *src, const mapbrush_t *mapbrush, int contents, const vec3_t rotate_offset, const int hullnum);
|
||||
enum class rotation_t {
|
||||
none, hipnotic, origin_brush
|
||||
};
|
||||
|
||||
brush_t *LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, int contents, const vec3_t rotate_offset, const rotation_t rottype, const int hullnum);
|
||||
void FreeBrushes(mapentity_t *ent);
|
||||
|
||||
int FindPlane(const vec3_t normal, const vec_t dist, int *side);
|
||||
|
|
|
|||
24
man/qbsp.1
24
man/qbsp.1
|
|
@ -133,6 +133,30 @@ brush which you don't want to generate bsp splits or portals. All
|
|||
surfaces of a hint brush must use either the \fIhint\fP or
|
||||
\fIhintskip\fP texture name.
|
||||
|
||||
.SS "ORIGIN"
|
||||
.PP
|
||||
An origin brush (all faces textured with "origin") can be added to a brush entity
|
||||
(but not detail or compiler-internal entities like func_group). Doing so causes all of
|
||||
the brushes in the brush entitiy to be translated so the center of the origin brush
|
||||
lines up with 0 0 0. The entity key "origin" is then automatically set on the
|
||||
brush entity to the original cooridnates of the center of the
|
||||
"origin" brush before it was translated to 0 0 0.
|
||||
.PP
|
||||
In Hexen 2, origin brushes are the native way of marking the center point of the
|
||||
rotation axis for rotating entities.
|
||||
.PP
|
||||
In Quake, origin brushes can be used to make some map hacks easier to set up
|
||||
that would otherwise require placing brushes at the world origin and
|
||||
entering an "origin" value by hand.
|
||||
.PP
|
||||
Note than, unlike the Hipnotic rotation support in QBSP, using origin brushes
|
||||
does not cause the model bounds to be expanded. (With Hipnotic rotation this was
|
||||
to ensure that the model is not vis culled, regardless of its rotated angle.)
|
||||
Origin brushes are useful for more than just rotation, and doing this bounds
|
||||
expansion would break some use cases, so if you're going to rotate a model
|
||||
with an origin brush you might need to expand the bounds of it a bit using
|
||||
clip brushes so it doesn't get vis culled.
|
||||
|
||||
.SH "EXTERNAL MAP PREFAB SUPPORT"
|
||||
.PP
|
||||
This qbsp has a prefab system using a point entity named "misc_external_map".
|
||||
|
|
|
|||
|
|
@ -363,8 +363,8 @@ CreateBrushFaces
|
|||
=================
|
||||
*/
|
||||
static face_t *
|
||||
CreateBrushFaces(const mapentity_t *src, hullbrush_t *hullbrush, const vec3_t rotate_offset,
|
||||
const int hullnum)
|
||||
CreateBrushFaces(const mapentity_t *src, hullbrush_t *hullbrush,
|
||||
const vec3_t rotate_offset, const rotation_t rottype, const int hullnum)
|
||||
{
|
||||
int i, j, k;
|
||||
vec_t r;
|
||||
|
|
@ -475,11 +475,20 @@ CreateBrushFaces(const mapentity_t *src, hullbrush_t *hullbrush, const vec3_t ro
|
|||
|
||||
// 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).
|
||||
const bool noExpand = static_cast<bool>(
|
||||
atoi(ValueForKey(src, "_no_bbox_rotation_expansion"))
|
||||
) || (hullnum < 0);
|
||||
|
||||
// Hexen2 also doesn't want the bbox expansion, it's handled in engine (see: SV_LinkEdict)
|
||||
|
||||
if ((rotate_offset[0] || rotate_offset[1] || rotate_offset[2]) && !noExpand) {
|
||||
// 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
|
||||
&& !options.hexen2; // never do this in Hexen 2
|
||||
|
||||
if (shouldExpand) {
|
||||
vec_t delta;
|
||||
|
||||
delta = fabs(max);
|
||||
|
|
@ -865,7 +874,7 @@ LoadBrush
|
|||
Converts a mapbrush to a bsp brush
|
||||
===============
|
||||
*/
|
||||
brush_t *LoadBrush(const mapentity_t *src, 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 rotation_t rottype, const int hullnum)
|
||||
{
|
||||
hullbrush_t hullbrush;
|
||||
brush_t *brush;
|
||||
|
|
@ -886,11 +895,11 @@ brush_t *LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, int conte
|
|||
|
||||
if (hullnum <= 0) {
|
||||
// for hull 0 or BSPX -wrbrushes collision, apply the rotation offset now
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
} else {
|
||||
// for Quake-style clipping hulls, don't apply rotation offset yet..
|
||||
// it will be applied below
|
||||
facelist = CreateBrushFaces(src, &hullbrush, vec3_origin, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, vec3_origin, rottype, hullnum);
|
||||
}
|
||||
|
||||
if (!facelist) {
|
||||
|
|
@ -905,19 +914,19 @@ brush_t *LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, int conte
|
|||
vec3_t size[2] = { {-16, -16, -36}, {16, 16, 36} };
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
}
|
||||
else if (hullnum == 2) {
|
||||
vec3_t size[2] = { {-32, -32, -32}, {32, 32, 32} };
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
}
|
||||
else if (hullnum == 3) {
|
||||
vec3_t size[2] = { {-16, -16, -18}, {16, 16, 18} };
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
}
|
||||
}
|
||||
else if (options.hexen2)
|
||||
|
|
@ -926,19 +935,19 @@ brush_t *LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, int conte
|
|||
vec3_t size[2] = { {-16, -16, -32}, {16, 16, 24} };
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
}
|
||||
else if (hullnum == 2) {
|
||||
vec3_t size[2] = { {-24, -24, -20}, {24, 24, 20} };
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
}
|
||||
else if (hullnum == 3) {
|
||||
vec3_t size[2] = { {-16, -16, -12}, {16, 16, 16} };
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
}
|
||||
else if (hullnum == 4) {
|
||||
#if 0
|
||||
|
|
@ -946,21 +955,21 @@ brush_t *LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, int conte
|
|||
vec3_t size[2] = { {-40, -40, -42}, {40, 40, 42} };
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
} else
|
||||
#endif
|
||||
{ /*mission pack*/
|
||||
vec3_t size[2] = { {-8, -8, -8}, {8, 8, 8} };
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
}
|
||||
}
|
||||
else if (hullnum == 5) {
|
||||
vec3_t size[2] = { {-48, -48, -50}, {48, 48, 50} };
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -970,13 +979,13 @@ brush_t *LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, int conte
|
|||
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
} else if (hullnum == 2) {
|
||||
vec3_t size[2] = { {-32, -32, -64}, {32, 32, 24} };
|
||||
|
||||
ExpandBrush(&hullbrush, size, facelist);
|
||||
FreeBrushFaces(facelist);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, hullnum);
|
||||
facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1108,7 +1117,7 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum)
|
|||
classname = ValueForKey(src, "classname");
|
||||
|
||||
/* Origin brush support */
|
||||
bool usesOriginBrush = false;
|
||||
rotation_t rottype = rotation_t::none;
|
||||
VectorCopy(vec3_origin, rotate_offset);
|
||||
|
||||
for (int i = 0; i < src->nummapbrushes; i++) {
|
||||
|
|
@ -1120,7 +1129,7 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum)
|
|||
continue;
|
||||
}
|
||||
|
||||
brush_t *brush = LoadBrush(src, mapbrush, contents, vec3_origin, 0);
|
||||
brush_t *brush = LoadBrush(src, mapbrush, contents, vec3_origin, rotation_t::none, 0);
|
||||
if (brush) {
|
||||
vec3_t origin;
|
||||
VectorAdd(brush->mins, brush->maxs, origin);
|
||||
|
|
@ -1131,7 +1140,7 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum)
|
|||
SetKeyValue(dst, "origin", value);
|
||||
|
||||
VectorCopy(origin, rotate_offset);
|
||||
usesOriginBrush = true;
|
||||
rottype = rotation_t::origin_brush;
|
||||
|
||||
FreeBrush(brush);
|
||||
}
|
||||
|
|
@ -1139,10 +1148,11 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum)
|
|||
}
|
||||
|
||||
/* Hipnotic rotation */
|
||||
if (!usesOriginBrush) {
|
||||
if (rottype == rotation_t::none) {
|
||||
if (!strncmp(classname, "rotate_", 7)) {
|
||||
FixRotateOrigin(dst);
|
||||
GetVectorForKey(dst, "origin", rotate_offset);
|
||||
rottype = rotation_t::hipnotic;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1245,7 +1255,7 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum)
|
|||
*/
|
||||
if (contents == CONTENTS_CLIP) {
|
||||
if (hullnum == 0) {
|
||||
brush_t *brush = LoadBrush(src, mapbrush, contents, rotate_offset, hullnum);
|
||||
brush_t *brush = LoadBrush(src, mapbrush, contents, rotate_offset, rottype, hullnum);
|
||||
if (brush) {
|
||||
AddToBounds(dst, brush->mins);
|
||||
AddToBounds(dst, brush->maxs);
|
||||
|
|
@ -1291,7 +1301,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(src, mapbrush, contents, rotate_offset, hullnum);
|
||||
brush_t *brush = LoadBrush(src, mapbrush, contents, rotate_offset, rottype, hullnum);
|
||||
if (!brush)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -2370,7 +2370,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(src, mapbrush, CONTENTS_SOLID, vec3_origin, 1);
|
||||
brush_t *hull1brush = LoadBrush(src, mapbrush, CONTENTS_SOLID, vec3_origin, rotation_t::none, 1);
|
||||
|
||||
if (hull1brush != nullptr)
|
||||
hull1brushes.push_back(hull1brush);
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ TEST(qbsp, duplicatePlanes) {
|
|||
EXPECT_EQ(0, worldspawn.numbrushes);
|
||||
EXPECT_EQ(6, worldspawn.mapbrush(0).numfaces);
|
||||
|
||||
brush_t *brush = LoadBrush(&worldspawn, &worldspawn.mapbrush(0), CONTENTS_SOLID, vec3_origin, 0);
|
||||
brush_t *brush = LoadBrush(&worldspawn, &worldspawn.mapbrush(0), CONTENTS_SOLID, vec3_origin, rotation_t::none, 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, &worldspawn.mapbrush(0), CONTENTS_SOLID, vec3_origin, 0);
|
||||
brush_t *brush = LoadBrush(&worldspawn, &worldspawn.mapbrush(0), CONTENTS_SOLID, vec3_origin, rotation_t::none, 0);
|
||||
Q_assert(nullptr != brush);
|
||||
|
||||
brush->contents = CONTENTS_SOLID;
|
||||
|
|
|
|||
Loading…
Reference in New Issue