sculpt-dev: Experimental: Flush sculpt data to mesh on autosave

This commit is contained in:
Joseph Eagar 2022-10-07 01:39:11 -07:00
parent 5e2b234855
commit e18be332b3
8 changed files with 212 additions and 1202 deletions

View File

@ -1427,7 +1427,7 @@ void BKE_sculptsession_free_vwpaint_data(SculptSession *ss)
/**
* Write out the sculpt dynamic-topology #BMesh to the #Mesh.
*/
static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
ATTR_NO_OPT static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
{
SculptSession *ss = ob->sculpt;

View File

@ -85,7 +85,7 @@ set(SRC
intern/bmesh_marking.h
intern/bmesh_mesh.cc
intern/bmesh_mesh.h
intern/bmesh_mesh_convert_threaded.c
intern/bmesh_mesh_convert_threaded.cc
intern/bmesh_mesh_convert.cc
intern/bmesh_mesh_convert.h
intern/bmesh_mesh_debug.c

View File

@ -4032,3 +4032,40 @@ bool BM_log_has_face_post(BMLog *log, BMFace *f)
return BLI_ghash_haskey(log->current_entry->topo_modified_faces_post,
POINTER_FROM_UINT(BM_ELEM_GET_ID(log->bm, f)));
}
void BM_log_get_changed(BMesh *bm, BMLogEntry *_entry, SmallHash *sh)
{
BMLogEntry *entry = _entry;
while (entry->combined_prev) {
entry = entry->combined_prev;
}
while (entry) {
GHashIterator gh_iter;
GHash **ghashes = &entry->topo_modified_verts_pre;
for (int i = 0; i < 9; i++) {
GHASH_ITER (gh_iter, ghashes[i]) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
uint id = POINTER_AS_UINT(key);
/* Note: elements are not guaranteed to exist */
if (id >= bm->idmap.map_size) {
continue;
}
BMElem *elem = BM_ELEM_FROM_ID(bm, id);
if (!elem) {
continue;
}
BLI_smallhash_reinsert(sh, (uintptr_t)elem, (void *)elem);
}
}
entry = entry->combined_next;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -149,6 +149,8 @@ typedef struct SculptUndoStep {
UndoSculpt data;
int id;
bool auto_saved;
// active vcol layer
SculptAttrRef active_attr_start;
SculptAttrRef active_attr_end;
@ -1228,7 +1230,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
bool need_refine_subdiv = false;
// bool did_first_hack = false;
bool clear_automask_cache = false;
bool clear_automask_cache = false;
for (unode = lb->first; unode; unode = unode->next) {
if (!ELEM(unode->type, SCULPT_UNDO_COLOR, SCULPT_UNDO_MASK)) {
@ -3075,3 +3077,115 @@ void SCULPT_substep_undo(bContext *C, int dir)
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
}
void BM_log_get_changed(BMesh *bm, BMLogEntry *_entry, SmallHash *sh);
void ED_sculpt_fast_save_bmesh(Object *ob)
{
SculptSession *ss = ob->sculpt;
BMesh *bm = ss->bm;
if (!bm || !ss) {
return;
}
#if 1
struct BMeshToMeshParams params = {0};
void BM_mesh_bm_to_me_threaded(
Main * bmain, Object * ob, BMesh * bm, Mesh * me, const struct BMeshToMeshParams *params);
params.update_shapekey_indices = true;
params.cd_mask_extra.vmask = CD_MASK_MESH_ID | CD_MASK_DYNTOPO_VERT;
params.cd_mask_extra.emask = CD_MASK_MESH_ID;
params.cd_mask_extra.pmask = CD_MASK_MESH_ID;
// BM_mesh_bm_to_me_threaded(NULL, ob, bm, (Mesh *)ob->data, &params);
BM_mesh_bm_to_me(NULL, ob, bm, (Mesh *)ob->data, &params);
#else
SculptUndoStep *last_step = NULL;
UndoStack *ustack = ED_undo_stack_get();
UndoStep *us = ustack->step_active;
SmallHash elems;
BLI_smallhash_init(&elems);
bool bad = false;
if (!us) {
printf("no active undo step!");
bad = true;
}
else {
while (us) {
us = us->prev;
if (us->type == BKE_UNDOSYS_TYPE_SCULPT) {
SculptUndoStep *usculpt = (SculptUndoStep *)us;
LISTBASE_FOREACH (SculptUndoNode *, unode, &usculpt->data.nodes) {
if (unode->bm_entry) {
BM_log_get_changed(bm, unode->bm_entry, &elems);
}
}
if (usculpt->auto_saved) {
last_step = usculpt;
break;
}
if (!last_step) {
usculpt->auto_saved = true;
}
last_step = usculpt;
}
}
}
if (!last_step) {
bad = true;
}
else {
last_step->auto_saved = true;
}
if (bad) {
printf("%s: Failed to find sculpt undo stack entries\n", __func__);
/* Just save everything */
struct BMeshToMeshParams params = {0};
BM_mesh_bm_to_me(NULL, ob, bm, (Mesh *)ob->data, &params);
return;
}
int totv = 0, tote = 0, totl = 0, totf = 0;
BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE | BM_LOOP | BM_FACE);
SmallHashIter iter;
uintptr_t key;
void *val = BLI_smallhash_iternew(&elems, &iter, &key);
for (; val; val = BLI_smallhash_iternext(&iter, &key)) {
BMElem *elem = (BMElem *)key;
switch (elem->head.htype) {
case BM_VERT:
totv++;
break;
case BM_EDGE:
tote++;
break;
case BM_LOOP:
totl++;
break;
case BM_FACE:
totf++;
break;
}
}
BLI_smallhash_release(&elems);
#endif
}

View File

@ -54,6 +54,11 @@ typedef struct MemFileUndoStep {
MemFileUndoData *data;
} MemFileUndoStep;
MemFileUndoData *memfile_get_step_data(MemFileUndoStep *us)
{
return us->data;
}
static bool memfile_undosys_poll(bContext *C)
{
/* other poll functions must run first, this is a catch-all. */

View File

@ -61,6 +61,8 @@ const EnumPropertyItem rna_enum_window_cursor_items[] = {
#ifdef RNA_RUNTIME
void wm_autosave_write(Main *bmain, wmWindowManager *wm);
# include "BKE_context.h"
# include "BKE_undo_system.h"
@ -114,6 +116,11 @@ static bool rna_event_modal_handler_add(struct bContext *C, struct wmOperator *o
return WM_event_add_modal_handler(C, operator) != NULL;
}
static void rna_WindowManager_autosave_write(struct wmWindowManager *wm, Main *main)
{
wm_autosave_write(main, wm);
}
/* XXX, need a way for python to know event types, 0x0110 is hard coded */
static wmTimer *rna_event_timer_add(struct wmWindowManager *wm, float time_step, wmWindow *win)
{
@ -763,6 +770,10 @@ void RNA_api_wm(StructRNA *srna)
FunctionRNA *func;
PropertyRNA *parm;
func = RNA_def_function(srna, "autosave_write", "rna_WindowManager_autosave_write");
RNA_def_function_ui_description(func, "Force autosave ");
RNA_def_function_flag(func, FUNC_USE_MAIN);
func = RNA_def_function(srna, "fileselect_add", "WM_event_add_fileselect");
RNA_def_function_ui_description(
func,

View File

@ -62,6 +62,7 @@
#include "BKE_asset_library.h"
#include "BKE_autoexec.h"
#include "BKE_blender.h"
#include "BKE_blender_undo.h"
#include "BKE_blendfile.h"
#include "BKE_callbacks.h"
#include "BKE_context.h"
@ -72,7 +73,9 @@
#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_main_namemap.h"
#include "BKE_multires.h"
#include "BKE_packedFile.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@ -1933,7 +1936,12 @@ static void wm_autosave_location(char filepath[FILE_MAX])
BLI_join_dirfile(filepath, FILE_MAX, tempdir_base, path);
}
static void wm_autosave_write(Main *bmain, wmWindowManager *wm)
/* TODO: Move to appropriate headers */
void ED_sculpt_fast_save_bmesh(Object *ob);
struct MemFileUndoStep;
MemFileUndoData *memfile_get_step_data(struct MemFileUndoStep *us);
ATTR_NO_OPT void wm_autosave_write(Main *bmain, wmWindowManager *wm)
{
char filepath[FILE_MAX];
@ -1942,8 +1950,41 @@ static void wm_autosave_write(Main *bmain, wmWindowManager *wm)
/* Fast save of last undo-buffer, now with UI. */
const bool use_memfile = (U.uiflag & USER_GLOBALUNDO) != 0;
MemFile *memfile = use_memfile ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : NULL;
bool update = false;
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if (ob->mode != OB_MODE_SCULPT || !ob->sculpt) {
continue;
}
/* Flush sculpt data to the mesh, we will append it to the undo memfile. */
if (ob->sculpt->bm) {
ED_sculpt_fast_save_bmesh(ob);
}
else {
multires_flush_sculpt_updates(ob);
}
update = true;
}
MemFileUndoData *mus = NULL;
if (update && memfile) {
UndoStep *us = BKE_undosys_stack_active_with_type(wm->undo_stack, BKE_UNDOSYS_TYPE_MEMFILE);
if (us) {
mus = memfile_get_step_data((struct MemFileUndoStep *)us);
mus = BKE_memfile_undo_encode(bmain, mus);
memfile = &mus->memfile;
}
}
if (memfile != NULL) {
BLO_memfile_write_file(memfile, filepath);
if (update) {
BKE_memfile_undo_free(mus);
}
}
else {
if (use_memfile) {