Add _hulls bmodel property

Whitelist hulls for which to generate clipnodes.
This commit is contained in:
Léo Peltier 2024-11-24 15:38:03 +01:00
parent d7eca5f317
commit 04e40951de
2 changed files with 43 additions and 0 deletions

View File

@ -819,6 +819,17 @@ Model Entity Keys
Defaults to 0, brushes with higher values (equivalent to appearing later in the .map file) will clip away lower Defaults to 0, brushes with higher values (equivalent to appearing later in the .map file) will clip away lower
valued brushes. valued brushes.
.. bmodel-key:: "_hulls" "n"
Bitmap ("Flags" type in FGD) that selects for which hulls collision data
will be generated. eg. a decimal value of 11 (0b1011) would generate hull 0, hull 1,
and hull 3.
Faces are computed using data from hull 0, not generating this hull will
prevent a bmodel from being rendered, acting as a CLIP brush only active for
the specified hulls.
Defaults to 0 which will generate clipnodes for all hulls.
.. bmodel-key:: "_chop" "n" .. bmodel-key:: "_chop" "n"
Set to 0 to prevent these brushes from being chopped. Set to 0 to prevent these brushes from being chopped.

View File

@ -985,6 +985,24 @@ static void GatherLeafVolumes_r(node_t *node, bspbrush_t::container &container)
GatherLeafVolumes_r(nodedata->children[1], container); GatherLeafVolumes_r(nodedata->children[1], container);
} }
/* Returns true if the user requested to generate an entity bmodel clipnodes
* for a given hull. */
static bool ShouldGenerateClipnodes(mapentity_t &entity, hull_index_t hullnum)
{
// Default to generating clipnodes for all hulls.
if (!entity.epairs.has("_hulls")) {
return true;
}
const int hulls = entity.epairs.get_int("_hulls");
// Ensure 0 means all hulls even in the case we have more than 32 hulls.
if (hulls == 0) {
return true;
}
return hulls & (1 << hullnum.value_or(0));
}
/* /*
=============== ===============
ProcessEntity ProcessEntity
@ -1089,6 +1107,16 @@ static void ProcessEntity(mapentity_t &entity, hull_index_t hullnum)
// simpler operation for hulls // simpler operation for hulls
if (hullnum.value_or(0)) { if (hullnum.value_or(0)) {
if (!ShouldGenerateClipnodes(entity, hullnum)) {
// We still need to emit an empty tree otherwise hull 0 will point past
// the clipnode array (FIXME?).
bspbrush_t::container empty;
tree_t tree;
BrushBSP(tree, entity, empty, tree_split_t::FAST);
ExportClipNodes(entity, tree.headnode, hullnum.value());
return;
}
tree_t tree; tree_t tree;
BrushBSP(tree, entity, brushes, tree_split_t::FAST); BrushBSP(tree, entity, brushes, tree_split_t::FAST);
if (map.is_world_entity(entity) && !qbsp_options.nofill.value()) { if (map.is_world_entity(entity) && !qbsp_options.nofill.value()) {
@ -1117,6 +1145,10 @@ static void ProcessEntity(mapentity_t &entity, hull_index_t hullnum)
return; return;
} }
if (!ShouldGenerateClipnodes(entity, hullnum)) {
return;
}
// full operation for collision (or main hull) // full operation for collision (or main hull)
tree_t tree; tree_t tree;