Skip to content

Commit

Permalink
qbsp: merge across liquids by default in q1
Browse files Browse the repository at this point in the history
- change option name to -nomergeacrossliquids
- add docs
- allow using it in q2 as well (requested by jitspoe)
  • Loading branch information
ericwa committed Jan 26, 2024
1 parent 6396f87 commit d512abd
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 15 deletions.
8 changes: 8 additions & 0 deletions docs/qbsp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ Options

Don't perform face merging.

.. option:: -nomergeacrossliquids

Don't merge faces above and below a liquid.

This is for maps targetting ezQuake (Q1) and Paintball2 (Q2) water caustics,
where the effect is applied per-face and breaks if a face is partially above
and partially below water.

.. option:: -noedgereuse

Don't reuse edges (may be useful for debugging software rendering).
Expand Down
2 changes: 1 addition & 1 deletion include/qbsp/qbsp.hh
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public:
setting_int32 subdivide;
setting_bool nofill;
setting_bool nomerge;
setting_bool mergeacrosswater;
setting_bool nomergeacrossliquids;
setting_bool noedgereuse;
setting_bool noclip;
setting_bool noskip;
Expand Down
21 changes: 10 additions & 11 deletions qbsp/merge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,19 @@ static std::unique_ptr<face_t> TryMerge(const face_t *f1, const face_t *f2)
f1->original_side->lmshift != f2->original_side->lmshift)
return NULL;

if (qbsp_options.target_game->id != GAME_QUAKE_II) {
if (!qbsp_options.mergeacrosswater.value()) {
// Q1: don't merge across water boundaries; ezQuake/nQuake water caustics will leak onto
// above-water faces.
if (f1->contents[0].is_liquid(qbsp_options.target_game) !=
f2->contents[0].is_liquid(qbsp_options.target_game))
return nullptr;
}

// Q1: don't merge across sky boundary - we delete faces inside sky
if (f1->contents[0].is_sky(qbsp_options.target_game) != f2->contents[0].is_sky(qbsp_options.target_game))
if (qbsp_options.nomergeacrossliquids.value()) {
// if requested, block merging across water boundaries;
// ezQuake/nQuake (Q1) and Paintball2 (Q2) water caustics will leak onto
// above-water faces.
if (f1->contents[0].is_liquid(qbsp_options.target_game) !=
f2->contents[0].is_liquid(qbsp_options.target_game))
return nullptr;
}

// Q1: don't merge across sky boundary - we delete faces inside sky
if (f1->contents[0].is_sky(qbsp_options.target_game) != f2->contents[0].is_sky(qbsp_options.target_game))
return nullptr;

// find a common edge
p1 = p2 = NULL; // stop compiler warning
j = 0; //
Expand Down
2 changes: 1 addition & 1 deletion qbsp/qbsp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ qbsp_settings::qbsp_settings()
"change the subdivide threshold, in luxels. 0 will disable subdivision entirely"},
nofill{this, "nofill", false, &debugging_group, "don't perform outside filling"},
nomerge{this, "nomerge", false, &debugging_group, "don't perform face merging"},
mergeacrosswater{this, "mergeacrosswater", false, &common_format_group, "merge faces that cross above and below water"},
nomergeacrossliquids{this, "nomergeacrossliquids", false, &common_format_group, "block merging faces that cross above and below water"},
noedgereuse{this, "noedgereuse", false, &debugging_group, "don't reuse edges (for debugging software rendering)"},
noclip{this, "noclip", false, &common_format_group, "don't write clip nodes (Q1-like BSP formats)"},
noskip{this, "noskip", false, &debugging_group, "don't remove faces with the 'skip' texture"},
Expand Down
3 changes: 1 addition & 2 deletions tests/test_qbsp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2126,7 +2126,7 @@ TEST_CASE("lq e3m4.map" * doctest::may_fail())
TEST_CASE("q1_tjunc_matrix")
{
// TODO: test opaque water in q1 mode
const auto [b, bspx, prt] = LoadTestmap("q1_tjunc_matrix.map", {"-mergeacrosswater"});
const auto [b, bspx, prt] = LoadTestmap("q1_tjunc_matrix.map");
const mbsp_t &bsp = b; // workaround clang not allowing capturing bindings in lambdas
auto *game = bsp.loadversion->game;

Expand Down Expand Up @@ -2175,7 +2175,6 @@ TEST_CASE("q1_tjunc_matrix")
CHECK(!has_tjunc(INDEX_SOLID, INDEX_DETAIL_FENCE_MIRRORINSIDE));
CHECK(!has_tjunc(INDEX_SOLID, INDEX_DETAIL_ILLUSIONARY));
CHECK(!has_tjunc(INDEX_SOLID, INDEX_DETAIL_ILLUSIONARY_NOCLIPFACES));
// "-mergeacrosswater" is needed to prevent a weld between transparent water and solid
CHECK(!has_tjunc(INDEX_SOLID, INDEX_WATER));
CHECK( has_tjunc(INDEX_SOLID, INDEX_SKY));
}
Expand Down

0 comments on commit d512abd

Please sign in to comment.