sculpt-dev: Experimental: Flush sculpt data to mesh on autosave
This commit is contained in:
parent
5e2b234855
commit
e18be332b3
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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, ¶ms);
|
||||
BM_mesh_bm_to_me(NULL, ob, bm, (Mesh *)ob->data, ¶ms);
|
||||
#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, ¶ms);
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue