Files
test2/source/blender/blenkernel/intern/blender_undo.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

150 lines
3.8 KiB
C++
Raw Normal View History

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*
* Blend file undo (known as 'Global Undo').
* DNA level diffing for undo.
*/
#ifndef _WIN32
# include <unistd.h> /* for read close */
#else
# include <io.h> /* for open close read */
#endif
#include <cerrno>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h> /* for open */
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_appdir.hh"
#include "BKE_blender_undo.hh" /* own include */
#include "BKE_blendfile.hh"
#include "BKE_context.hh"
#include "BKE_global.h"
#include "BKE_main.hh"
2024-01-15 12:26:09 -05:00
#include "BKE_undo_system.hh"
#include "BLO_readfile.h"
#include "BLO_undofile.hh"
#include "BLO_writefile.hh"
#include "DEG_depsgraph.hh"
/* -------------------------------------------------------------------- */
/** \name Global Undo
* \{ */
#define UNDO_DISK 0
bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
const eUndoStepDir undo_direction,
const bool use_old_bmain_data,
bContext *C)
{
Main *bmain = CTX_data_main(C);
char mainstr[sizeof(bmain->filepath)];
int success = 0, fileflags;
2023-05-09 12:50:37 +10:00
STRNCPY(mainstr, BKE_main_blendfile_path(bmain)); /* temporal store */
fileflags = G.fileflags;
G.fileflags |= G_FILE_NO_UI;
if (UNDO_DISK) {
const BlendFileReadParams params{};
BlendFileReadReport bf_reports{};
BlendFileData *bfd = BKE_blendfile_read(mfu->filepath, &params, &bf_reports);
if (bfd != nullptr) {
Readfile: Refactor several parts of the process This commit affects: * Reading undo steps from memfile (aka 'Global Undo'); * Handling of UI IDs (WindowManager, Workspaces and Screens) when opening a .blend file. While no major changes are expected from a user PoV, there may be some unexpected changes in rare edge-cases. None has been identified so far. Undo step loading should be marginally faster (`setup_app_data` itself is 2-3 times faster, as it does not do remapping anymore, which makes the whole 'read undo step' process about 20% faster - but the most time-consuming step on undo is the depsgraph processing, which remains unchanged here). This commit also solves some bugs (crashes) in some relatively uncommon cases, like e.g. if the WM had an IDProperty pointing at an object and UI is not loaded when opening a new .blend file with the 'Load UI' option enabled (as in previous code on file opening WM ID would never be remapped). From a more technical side, this commit aims mainly at cleaning things up, in preparation for the introduction of new 'no undo, no readfile' type of handling (as part of the Brush Assets project): - Prevent WM code from doing (too much) horrible ID 'management' on its WM when opening a new file. It used to remove current WM from the Main database, store it in a temporary own list, and then free it itself... - Trying to make the complex logic behind WM handling on file reading a bit more easy to follow, at least way more documented in code. - Keep the handling of 'IDs being re-used from old Main' in a single place, as much as possible: -- Readfile code itself in undo case (because it's more efficient, and undo case is in a way simpler than actual .blend file reading case). The whole `blo_lib_link_restore` block of code is also removed. -- (Mostly) setup_app_data code in actual file reading case. - Sanitize the usage of the 'libmap' in readfile code in undo case (waaaaay too many pointers were added there, which was hiding some other issues in the related code, and potentially causing (in rare cases) memory addresses collisions. Pull Request: https://projects.blender.org/blender/blender/pulls/108016
2023-06-05 13:54:49 +02:00
BKE_blendfile_read_setup_undo(C, bfd, &params, &bf_reports);
success = true;
}
}
else {
BlendFileReadParams params = {0};
params.undo_direction = undo_direction;
if (!use_old_bmain_data) {
params.skip_flags |= BLO_READ_SKIP_UNDO_OLD_MAIN;
}
BlendFileReadReport blend_file_read_report{};
BlendFileData *bfd = BKE_blendfile_read_from_memfile(bmain, &mfu->memfile, &params, nullptr);
if (bfd != nullptr) {
Readfile: Refactor several parts of the process This commit affects: * Reading undo steps from memfile (aka 'Global Undo'); * Handling of UI IDs (WindowManager, Workspaces and Screens) when opening a .blend file. While no major changes are expected from a user PoV, there may be some unexpected changes in rare edge-cases. None has been identified so far. Undo step loading should be marginally faster (`setup_app_data` itself is 2-3 times faster, as it does not do remapping anymore, which makes the whole 'read undo step' process about 20% faster - but the most time-consuming step on undo is the depsgraph processing, which remains unchanged here). This commit also solves some bugs (crashes) in some relatively uncommon cases, like e.g. if the WM had an IDProperty pointing at an object and UI is not loaded when opening a new .blend file with the 'Load UI' option enabled (as in previous code on file opening WM ID would never be remapped). From a more technical side, this commit aims mainly at cleaning things up, in preparation for the introduction of new 'no undo, no readfile' type of handling (as part of the Brush Assets project): - Prevent WM code from doing (too much) horrible ID 'management' on its WM when opening a new file. It used to remove current WM from the Main database, store it in a temporary own list, and then free it itself... - Trying to make the complex logic behind WM handling on file reading a bit more easy to follow, at least way more documented in code. - Keep the handling of 'IDs being re-used from old Main' in a single place, as much as possible: -- Readfile code itself in undo case (because it's more efficient, and undo case is in a way simpler than actual .blend file reading case). The whole `blo_lib_link_restore` block of code is also removed. -- (Mostly) setup_app_data code in actual file reading case. - Sanitize the usage of the 'libmap' in readfile code in undo case (waaaaay too many pointers were added there, which was hiding some other issues in the related code, and potentially causing (in rare cases) memory addresses collisions. Pull Request: https://projects.blender.org/blender/blender/pulls/108016
2023-06-05 13:54:49 +02:00
BKE_blendfile_read_setup_undo(C, bfd, &params, &blend_file_read_report);
success = true;
}
}
/* Restore, bmain has been re-allocated. */
bmain = CTX_data_main(C);
STRNCPY(bmain->filepath, mainstr);
G.fileflags = fileflags;
if (success) {
/* important not to update time here, else non keyed transforms are lost */
DEG_tag_on_visible_update(bmain, false);
}
return success;
}
MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
{
MemFileUndoData *mfu = MEM_cnew<MemFileUndoData>(__func__);
/* Include recovery information since undo-data is written out as #BLENDER_QUIT_FILE. */
const int fileflags = G.fileflags | G_FILE_RECOVER_WRITE;
/* disk save version */
if (UNDO_DISK) {
static int counter = 0;
char filepath[FILE_MAX];
char numstr[32];
/* Calculate current filepath. */
counter++;
counter = counter % U.undosteps;
2023-05-09 12:50:37 +10:00
SNPRINTF(numstr, "%d.blend", counter);
BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_session(), numstr);
const BlendFileWriteParams blend_file_write_params{};
/* success = */ /* UNUSED */ BLO_write_file(
bmain, filepath, fileflags, &blend_file_write_params, nullptr);
2023-05-09 12:50:37 +10:00
STRNCPY(mfu->filepath, filepath);
}
else {
MemFile *prevfile = (mfu_prev) ? &(mfu_prev->memfile) : nullptr;
if (prevfile) {
BLO_memfile_clear_future(prevfile);
}
/* success = */ /* UNUSED */ BLO_write_file_mem(bmain, prevfile, &mfu->memfile, fileflags);
mfu->undo_size = mfu->memfile.size;
}
bmain->is_memfile_undo_written = true;
return mfu;
}
void BKE_memfile_undo_free(MemFileUndoData *mfu)
{
BLO_memfile_free(&mfu->memfile);
MEM_freeN(mfu);
}
/** \} */