From 49a45745e486fb082dfba4eafb65514feedbb7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Mon, 29 Dec 2025 13:17:45 +0100 Subject: [PATCH] spline undo fixes #1411 --- Editor/Editor.cpp | 14 ++++++++++++++ Editor/Editor.h | 1 + Editor/SplineWindow.cpp | 11 +++++++++++ WickedEngine/wiTerrain.cpp | 29 ++++++++++++++++++++++++++--- WickedEngine/wiVersion.cpp | 2 +- 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index 919502a12..364870657 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -5041,6 +5041,7 @@ void EditorComponent::ConsumeHistoryOperation(bool undo) } break; case HISTORYOP_ADD: + case HISTORYOP_ADD_TO_SPLINE: { // Read selections states from archive: @@ -5074,6 +5075,19 @@ void EditorComponent::ConsumeHistoryOperation(bool undo) selectedAFTER.push_back(sel); } + if (type == HISTORYOP_ADD_TO_SPLINE) + { + wi::vector modifiedSplineEntities; + archive >> modifiedSplineEntities; + EntitySerializer seri; + seri.allow_remap = false; + for (size_t i = 0; i < modifiedSplineEntities.size(); ++i) + { + scene.Entity_Remove(modifiedSplineEntities[i], false); // no recursive!!! + scene.Entity_Serialize(archive, seri, INVALID_ENTITY, wi::scene::Scene::EntitySerializeFlags::KEEP_INTERNAL_ENTITY_REFERENCES); // no recursive!!! + } + } + wi::vector addedEntities; archive >> addedEntities; diff --git a/Editor/Editor.h b/Editor/Editor.h index 3e14d5e46..1def92561 100644 --- a/Editor/Editor.h +++ b/Editor/Editor.h @@ -167,6 +167,7 @@ public: HISTORYOP_DELETE, // entity removed HISTORYOP_COMPONENT_DATA, // generic component data changed HISTORYOP_PAINTTOOL, // paint tool interaction + HISTORYOP_ADD_TO_SPLINE, // Spline node added HISTORYOP_NONE }; diff --git a/Editor/SplineWindow.cpp b/Editor/SplineWindow.cpp index 25f860a4a..b7d180ade 100644 --- a/Editor/SplineWindow.cpp +++ b/Editor/SplineWindow.cpp @@ -335,8 +335,19 @@ void SplineWindow::NewNode() spline->spline_node_transforms.push_back(transform); scene.Component_Attach(node_entity, entity); RefreshEntries(); + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD_TO_SPLINE; + editor->RecordSelection(archive); + editor->ClearSelected(); editor->AddSelected(node_entity); + + editor->RecordSelection(archive); + + editor->RecordEntity(archive, entity); + editor->RecordEntity(archive, node_entity); + editor->componentsWnd.RefreshEntityTree(); } diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index 5bd8f1d21..4d4955ccb 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -184,6 +184,7 @@ namespace wi::terrain wi::jobsystem::context workload; std::atomic_bool cancelled{ false }; wi::vector splines; + wi::vector spline_entities; wi::vector removable_chunks; // chunks that were invalidated are regenerated on the generator thread. Before merging them with the scene, the previous version of them will need to be removed from the destination scene std::deque priority_invalidation; // to not let invalidation stuck at same chunks every frame while editing splines, for more appealing visual feedback }; @@ -928,21 +929,43 @@ namespace wi::terrain terrain_spline_count_scene++; } } - if (terrain_spline_count_scene != generator->splines.size()) + // Check mismatches between current and previous slines (removal, undo, etc.) + for (size_t i = 0; i < generator->splines.size(); ++i) { - // Need to invalidate terrain if spline was removed: - for (const SplineComponent& spline : generator->splines) + const SplineComponent& spline = generator->splines[i]; + Entity entity = generator->spline_entities[i]; + bool invalidation_required = false; + invalidation_required |= !scene->splines.Contains(entity); // no longer exists in scene, was deleted + if (!invalidation_required) + { + // If spline exists in scene, need to compare for changes: + const SplineComponent& other = *scene->splines.GetComponent(entity); + invalidation_required |= spline.width != other.width; + invalidation_required |= spline.rotation != other.rotation; + invalidation_required |= spline.terrain_modifier_amount != other.terrain_modifier_amount; + invalidation_required |= spline.terrain_pushdown != other.terrain_pushdown; + invalidation_required |= spline.terrain_texture_falloff != other.terrain_texture_falloff; + invalidation_required |= spline.spline_node_transforms.size() != other.spline_node_transforms.size(); + if (!invalidation_required) + { + // Last resort compare whole node transform array: + invalidation_required |= std::memcmp(spline.spline_node_transforms.data(), other.spline_node_transforms.data(), spline.spline_node_transforms.size() * sizeof(TransformComponent)) != 0; + } + } + if (invalidation_required) { InvalidateChunksAtSpline(spline); } } generator->splines.clear(); + generator->spline_entities.clear(); for (size_t i = 0; i < scene->splines.GetCount(); ++i) { const SplineComponent& spline = scene->splines[i]; if (spline.terrain_modifier_amount > 0) { generator->splines.push_back(spline); + generator->spline_entities.push_back(scene->splines.GetEntity(i)); } } wi::jobsystem::Execute(generator->workload, [=](wi::jobsystem::JobArgs a) { diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 04032956d..765cb8110 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 869; + const int revision = 870; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);