From bd6e5fe3de9c4ca4dc5c7c073607876f4deecb20 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 07:37:54 -0700 Subject: [PATCH] fix(brush): reject NaN/non-positive brush settings before sculpt apply MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same NaN-comparison short-circuit bug as the texture painter — a brush with a NaN cursor position would mark every vertex in every 'affected' chunk as full influence and silently rewrite huge swaths of terrain. Reject upfront in applyBrush. --- tools/editor/terrain_editor.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/editor/terrain_editor.cpp b/tools/editor/terrain_editor.cpp index e653afa5..88518a14 100644 --- a/tools/editor/terrain_editor.cpp +++ b/tools/editor/terrain_editor.cpp @@ -289,8 +289,17 @@ void TerrainEditor::commitGeneratorUndo() { void TerrainEditor::applyBrush(float deltaTime) { if (!terrain_ || !brush_.isActive()) return; + // Reject NaN brush position / non-positive radius / NaN strength. + // dist = length(pos - center) goes NaN if center has NaN, and + // brush_.getInfluence(NaN) returns full strength on every vertex + // because NaN comparisons always return false. + const auto& bs = brush_.settings(); + auto bp = brush_.getPosition(); + if (!std::isfinite(bp.x) || !std::isfinite(bp.y) || !std::isfinite(bp.z) || + !std::isfinite(bs.radius) || bs.radius <= 0.0f || + !std::isfinite(bs.strength)) return; - switch (brush_.settings().mode) { + switch (bs.mode) { case BrushMode::Raise: applyRaise(deltaTime); break; case BrushMode::Lower: applyRaise(deltaTime); break; case BrushMode::Smooth: applySmooth(deltaTime); break;