From 5366c537346a6bf85ee63d2fe14078b00d9b3eed Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 07:45:26 -0700 Subject: [PATCH] fix(objects): NaN guards on transform deltas A NaN move/rotate/scale delta would poison every selected object's transform permanently and produce NaN model matrices in the renderer. Reject upfront. --- tools/editor/object_placer.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/editor/object_placer.cpp b/tools/editor/object_placer.cpp index b3cbf93d..cecd9ee0 100644 --- a/tools/editor/object_placer.cpp +++ b/tools/editor/object_placer.cpp @@ -134,6 +134,10 @@ void ObjectPlacer::selectByType(PlaceableType type) { } void ObjectPlacer::moveSelected(const glm::vec3& delta) { + // NaN delta would poison every selected position permanently — + // the renderer would then produce NaN model matrices. + if (!std::isfinite(delta.x) || !std::isfinite(delta.y) || + !std::isfinite(delta.z)) return; if (selectedIndices_.size() > 1) { for (int idx : selectedIndices_) objects_[idx].position += delta; } else if (auto* obj = getSelected()) { @@ -142,6 +146,8 @@ void ObjectPlacer::moveSelected(const glm::vec3& delta) { } void ObjectPlacer::rotateSelected(const glm::vec3& deltaDeg) { + if (!std::isfinite(deltaDeg.x) || !std::isfinite(deltaDeg.y) || + !std::isfinite(deltaDeg.z)) return; if (selectedIndices_.size() > 1) { for (int idx : selectedIndices_) objects_[idx].rotation += deltaDeg; } else if (auto* obj = getSelected()) { @@ -150,6 +156,7 @@ void ObjectPlacer::rotateSelected(const glm::vec3& deltaDeg) { } void ObjectPlacer::scaleSelected(float delta) { + if (!std::isfinite(delta)) return; if (selectedIndices_.size() > 1) { for (int idx : selectedIndices_) objects_[idx].scale = std::max(0.1f, objects_[idx].scale + delta);