From bc090387ace9cf041455fa01e68d61551c47e18f Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 12 Nov 2020 10:41:33 +0100 Subject: Fix T82388: Sculpt mode: Unexpected undo behavior. Issue exposed by rB4c7b1766a7f1. Main idea is that non-memfile first undo step should check into previous memfile and tag the ID it is editing as `future_changed`. That way, when we go back and undo to the memfile, said IDs are properly detected as changed and re-read from the memfile. Otherwise, undo system sees them as unchanged, and just re-use the current data instead. Note that currently only Sculpt mode seems affected (probably because it is storing the mode switch itself as a Sculpt undo step instead of a memfile one), but similar action might be needed in some other cases too. Maniphest Tasks: T82388 Differential Revision: https://developer.blender.org/D9510 --- source/blender/editors/undo/memfile_undo.c | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'source/blender/editors/undo/memfile_undo.c') diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index 2df26abe8b3..ace82f82a78 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -24,7 +24,9 @@ #include "BLI_utildefines.h" #include "BLI_ghash.h" +#include "BLI_listbase.h" +#include "DNA_ID.h" #include "DNA_node_types.h" #include "DNA_object_enums.h" #include "DNA_object_types.h" @@ -52,6 +54,8 @@ #include "undo_intern.h" +#include + /* -------------------------------------------------------------------- */ /** \name Implements ED Undo System * \{ */ @@ -307,4 +311,35 @@ struct MemFile *ED_undosys_stack_memfile_get_active(UndoStack *ustack) return NULL; } +/** + * If the last undo step is a memfile one, find the first memchunk matching given ID (using its + * seesion uuid), and tag it as 'changed in the future'. + * + * Since non-memfile undos cannot automatically set this flag in the previous step as done with + * memfile ones, this has to be called manually by relevant undo code. + * + * \note Only current known case for this is undoing a switch from Pbject to Sculpt mode (see + * T82388). + * + * \note Calling this ID by ID is not optimal, as it will loop over all memchunks until it find + * expected one. If this becomes an issue we'll have to add a mapping from session uuid to first + * memchunk in #MemFile itself (currently we only do that in #MemFileWriteData when writing a new + * step). + */ +void ED_undosys_stack_memfile_id_changed_tag(UndoStack *ustack, ID *id) +{ + UndoStep *us = ustack->step_active; + if (id == NULL || us == NULL || us->type != BKE_UNDOSYS_TYPE_MEMFILE) { + return; + } + + MemFile *memfile = &((MemFileUndoStep *)us)->data->memfile; + LISTBASE_FOREACH (MemFileChunk *, mem_chunk, &memfile->chunks) { + if (mem_chunk->id_session_uuid == id->session_uuid) { + mem_chunk->is_identical_future = false; + break; + } + } +} + /** \} */ -- cgit v1.2.3