qbsp: add -bmodelcontents flag

This commit is contained in:
Eric Wasylishen 2023-04-22 19:15:55 -06:00
parent 17f8abff33
commit 50d97321d7
6 changed files with 116 additions and 1 deletions

View File

@ -164,6 +164,14 @@ Options
"-wrbrushes" combined with "-noclip" argument. This is NOT backwards "-wrbrushes" combined with "-noclip" argument. This is NOT backwards
compatible. compatible.
.. option:: -bmodelcontents
Allow bmodels to have contents other than "solid" in Q1 based games,
e.g. water in a func_door. This is supported in FTEQW; in winquake,
the bmodel will have no collision.
Q2 supports this feature natively and this option has no effect.
.. option:: -notex .. option:: -notex
Write only placeholder textures, to depend upon replacements. This Write only placeholder textures, to depend upon replacements. This

View File

@ -212,6 +212,7 @@ public:
setting_bool objexport; setting_bool objexport;
setting_bool wrbrushes; setting_bool wrbrushes;
setting_redirect wrbrushesonly; setting_redirect wrbrushesonly;
setting_bool bmodelcontents;
setting_bool omitdetail; setting_bool omitdetail;
setting_bool omitdetailwall; setting_bool omitdetailwall;
setting_bool omitdetailillusionary; setting_bool omitdetailillusionary;

View File

@ -790,7 +790,8 @@ static void Brush_LoadEntity(mapentity_t &dst, mapentity_t &src, hull_index_t hu
} }
/* entities in some games never use water merging */ /* entities in some games never use water merging */
if (!map.is_world_entity(dst) && !qbsp_options.target_game->allow_contented_bmodels) { if (!map.is_world_entity(dst) &&
!(qbsp_options.target_game->allow_contented_bmodels || qbsp_options.bmodelcontents.value())) {
// bmodels become solid in Q1 // bmodels become solid in Q1
// to allow use of _mirrorinside, we'll set it to detail fence, which will get remapped back // to allow use of _mirrorinside, we'll set it to detail fence, which will get remapped back

View File

@ -538,6 +538,8 @@ qbsp_settings::qbsp_settings()
"includes a list of brushes for brush-based collision"}, "includes a list of brushes for brush-based collision"},
wrbrushesonly{this, {"wrbrushesonly", "bspxonly"}, {&wrbrushes, &noclip}, &common_format_group, wrbrushesonly{this, {"wrbrushesonly", "bspxonly"}, {&wrbrushes, &noclip}, &common_format_group,
"includes BSPX brushes and does not output clipping hulls (wrbrushes + noclip)"}, "includes BSPX brushes and does not output clipping hulls (wrbrushes + noclip)"},
bmodelcontents{this, "bmodelcontents", false, &common_format_group,
"allow control over brush contents in bmodels, don't force CONTENTS_SOLID"},
omitdetail{this, "omitdetail", false, &map_development_group, "omit *all* detail brushes from the compile"}, omitdetail{this, "omitdetail", false, &map_development_group, "omit *all* detail brushes from the compile"},
omitdetailwall{this, "omitdetailwall", false, &map_development_group, omitdetailwall{this, "omitdetailwall", false, &map_development_group,
"func_detail_wall brushes are omitted from the compile"}, "func_detail_wall brushes are omitted from the compile"},

View File

@ -0,0 +1,88 @@
// Game: Quake
// Format: Valve
// entity 0
{
"mapversion" "220"
"classname" "worldspawn"
"wad" "deprecated/free_wad.wad;deprecated/fence.wad;deprecated/origin.wad;deprecated/hintskip.wad"
"_wateralpha" "0.5"
"_tb_def" "builtin:Quake.fgd"
// brush 0
{
( -112 -112 96 ) ( -112 -111 96 ) ( -112 -112 97 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 0 ] 0 2 2
( -80 -272 80 ) ( -81 -272 80 ) ( -80 -272 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2
( -80 -432 80 ) ( -80 -431 80 ) ( -81 -432 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 2 2
( -160 -112 96 ) ( -161 -112 96 ) ( -160 -111 96 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 2 2
( -160 0 96 ) ( -160 0 97 ) ( -161 0 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2
( 64 -432 80 ) ( 64 -432 81 ) ( 64 -431 80 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 2 2
}
// brush 1
{
( -112 -96 96 ) ( -112 -95 96 ) ( -112 -96 97 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 0 ] 0 2 2
( -80 0 80 ) ( -81 0 80 ) ( -80 0 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2
( -80 -416 80 ) ( -80 -415 80 ) ( -81 -416 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 2 2
( -160 -96 224 ) ( -161 -96 224 ) ( -160 -95 224 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 2 2
( -160 16 96 ) ( -160 16 97 ) ( -161 16 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2
( 64 -416 80 ) ( 64 -416 81 ) ( 64 -415 80 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 2 2
}
// brush 2
{
( -112 -384 96 ) ( -112 -383 96 ) ( -112 -384 97 ) orangestuff8 [ 0 1 0 8 ] [ 0 0 -1 0 ] 0 2 2
( -80 -288 80 ) ( -81 -288 80 ) ( -80 -288 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2
( -80 -704 80 ) ( -80 -703 80 ) ( -81 -704 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 -8 ] 180 2 2
( -160 -384 224 ) ( -161 -384 224 ) ( -160 -383 224 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 -8 ] 180 2 2
( -160 -272 96 ) ( -160 -272 97 ) ( -161 -272 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2
( 64 -704 80 ) ( 64 -704 81 ) ( 64 -703 80 ) orangestuff8 [ 0 -1 0 -8 ] [ 0 0 -1 0 ] 0 2 2
}
// brush 3
{
( -128 -112 96 ) ( -128 -111 96 ) ( -128 -112 97 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 0 ] 0 2 2
( -256 -272 80 ) ( -257 -272 80 ) ( -256 -272 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2
( -256 -432 80 ) ( -256 -431 80 ) ( -257 -432 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 2 2
( -336 -112 224 ) ( -337 -112 224 ) ( -336 -111 224 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 2 2
( -336 0 96 ) ( -336 0 97 ) ( -337 0 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2
( -112 -432 80 ) ( -112 -432 81 ) ( -112 -431 80 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 2 2
}
// brush 4
{
( 64 -112 96 ) ( 64 -111 96 ) ( 64 -112 97 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 0 ] 0 2 2
( -64 -272 80 ) ( -65 -272 80 ) ( -64 -272 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2
( -64 -432 80 ) ( -64 -431 80 ) ( -65 -432 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 2 2
( -144 -112 224 ) ( -145 -112 224 ) ( -144 -111 224 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 2 2
( -144 0 96 ) ( -144 0 97 ) ( -145 0 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2
( 80 -432 80 ) ( 80 -432 81 ) ( 80 -431 80 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 2 2
}
// brush 5
{
( -112 -112 240 ) ( -112 -111 240 ) ( -112 -112 241 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 0 ] 0 2 2
( -80 -272 224 ) ( -81 -272 224 ) ( -80 -272 225 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2
( -80 -432 224 ) ( -80 -431 224 ) ( -81 -432 224 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 2 2
( -160 -112 240 ) ( -161 -112 240 ) ( -160 -111 240 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 2 2
( -160 0 240 ) ( -160 0 241 ) ( -161 0 240 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2
( 64 -432 224 ) ( 64 -432 225 ) ( 64 -431 224 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 2 2
}
}
// entity 1
{
"classname" "info_player_start"
"origin" "-88 -64 120"
}
// entity 2
{
"classname" "func_wall"
"_mirrorinside" "1"
// brush 0
{
( -16 -140 112 ) ( -16 -139 112 ) ( -16 -140 113 ) *swater4 [ 0 -1 0 -16 ] [ 0 0 -1 16 ] 0 1 1
( -8 -144 112 ) ( -8 -144 113 ) ( -7 -144 112 ) *swater4 [ 1 0 0 16 ] [ 0 0 -1 16 ] 0 1 1
( -8 -140 112 ) ( -7 -140 112 ) ( -8 -139 112 ) *swater4 [ -1 0 0 -16 ] [ 0 -1 0 -16 ] 0 1 1
( 56 -92 208 ) ( 56 -91 208 ) ( 57 -92 208 ) *swater4 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 0 1 1
( 56 -96 128 ) ( 57 -96 128 ) ( 56 -96 129 ) *swater4 [ -1 0 0 -16 ] [ 0 0 -1 16 ] 0 1 1
( 32 -92 128 ) ( 32 -92 129 ) ( 32 -91 128 ) *swater4 [ 0 1 0 16 ] [ 0 0 -1 16 ] 0 1 1
}
}
// entity 3
{
"classname" "ambient_swamp1"
"origin" "-24 -136 152"
}

View File

@ -728,6 +728,21 @@ TEST_CASE("qbsp_bmodel_mirrorinside_with_liquid" * doctest::test_suite("testmaps
} }
} }
TEST_CASE("q1_bmodel_liquid" * doctest::test_suite("testmaps_q1"))
{
const auto [bsp, bspx, prt] = LoadTestmapQ1("q1_bmodel_liquid.map", {"-bmodelcontents"});
REQUIRE(prt.has_value());
// nonsolid brushes don't show up in clipping hulls. so 6 for the box room in hull1, and 6 for hull2.
REQUIRE(12 == bsp.dclipnodes.size());
const auto inside_water = qvec3d{8, -120, 184};
CHECK(CONTENTS_WATER == BSP_FindContentsAtPoint(&bsp, {0}, &bsp.dmodels[1], inside_water));
CHECK(CONTENTS_EMPTY == BSP_FindContentsAtPoint(&bsp, {1}, &bsp.dmodels[1], inside_water));
CHECK(CONTENTS_EMPTY == BSP_FindContentsAtPoint(&bsp, {2}, &bsp.dmodels[1], inside_water));
}
TEST_CASE("noclipfaces" * doctest::test_suite("testmaps_q1")) TEST_CASE("noclipfaces" * doctest::test_suite("testmaps_q1"))
{ {
const auto [bsp, bspx, prt] = LoadTestmapQ1("qbsp_noclipfaces.map"); const auto [bsp, bspx, prt] = LoadTestmapQ1("qbsp_noclipfaces.map");