Skip to content

Commit

Permalink
Add _hulls bmodel property
Browse files Browse the repository at this point in the history
Whitelist hulls for which to generate clipnodes.
  • Loading branch information
L-P committed Nov 26, 2024
1 parent 4e11e3e commit ac802a5
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 0 deletions.
11 changes: 11 additions & 0 deletions docs/qbsp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
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"

Set to 0 to prevent these brushes from being chopped.
Expand Down
32 changes: 32 additions & 0 deletions qbsp/qbsp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,24 @@ static void GatherLeafVolumes_r(node_t *node, bspbrush_t::container &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
Expand Down Expand Up @@ -1089,6 +1107,16 @@ static void ProcessEntity(mapentity_t &entity, hull_index_t hullnum)

// simpler operation for hulls
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;
BrushBSP(tree, entity, brushes, tree_split_t::FAST);
if (map.is_world_entity(entity) && !qbsp_options.nofill.value()) {
Expand Down Expand Up @@ -1117,6 +1145,10 @@ static void ProcessEntity(mapentity_t &entity, hull_index_t hullnum)
return;
}

if (!ShouldGenerateClipnodes(entity, hullnum)) {
return;
}

// full operation for collision (or main hull)
tree_t tree;

Expand Down

0 comments on commit ac802a5

Please sign in to comment.