diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_undo.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_undo.c | 634 |
1 files changed, 575 insertions, 59 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 501a1e53276..df4b43d21a2 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -113,9 +113,11 @@ typedef struct UndoSculpt { ListBase nodes; size_t undo_size; + BMLog *bm_restore; } UndoSculpt; static UndoSculpt *sculpt_undo_get_nodes(void); +void sculpt_undo_print_nodes(void *active); static void update_cb(PBVHNode *node, void *rebuild) { @@ -133,6 +135,8 @@ struct PartialUpdateData { char *modified_grids; }; +static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p); + /** * A version of #update_cb that tests for 'ME_VERT_PBVH_UPDATE' */ @@ -170,6 +174,8 @@ static bool test_swap_v3_v3(float a[3], float b[3]) return false; } +void pbvh_bmesh_check_nodes(PBVH *pbvh); + static bool sculpt_undo_restore_deformed( const SculptSession *ss, SculptUndoNode *unode, int uindex, int oindex, float coord[3]) { @@ -187,7 +193,7 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt SculptSession *ss = ob->sculpt; SubdivCCG *subdiv_ccg = ss->subdiv_ccg; MVert *mvert; - int *index; + SculptVertRef *index; if (unode->maxvert) { /* Regular mesh restore. */ @@ -221,18 +227,18 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt if (unode->orig_co) { if (ss->deform_modifiers_active) { for (int i = 0; i < unode->totvert; i++) { - sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]); + sculpt_undo_restore_deformed(ss, unode, i, index[i].i, vertCos[index[i].i]); } } else { for (int i = 0; i < unode->totvert; i++) { - swap_v3_v3(vertCos[index[i]], unode->orig_co[i]); + swap_v3_v3(vertCos[index[i].i], unode->orig_co[i]); } } } else { for (int i = 0; i < unode->totvert; i++) { - swap_v3_v3(vertCos[index[i]], unode->co[i]); + swap_v3_v3(vertCos[index[i].i], unode->co[i]); } } @@ -249,21 +255,21 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt if (unode->orig_co) { if (ss->deform_modifiers_active) { for (int i = 0; i < unode->totvert; i++) { - sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co); - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; + sculpt_undo_restore_deformed(ss, unode, i, index[i].i, mvert[index[i].i].co); + mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE; } } else { for (int i = 0; i < unode->totvert; i++) { - swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]); - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; + swap_v3_v3(mvert[index[i].i].co, unode->orig_co[i]); + mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE; } } } else { for (int i = 0; i < unode->totvert; i++) { - swap_v3_v3(mvert[index[i]].co, unode->co[i]); - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; + swap_v3_v3(mvert[index[i].i].co, unode->co[i]); + mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE; } } } @@ -303,7 +309,7 @@ static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode) MVert *mvert = ss->mvert; for (int i = 0; i < unode->totvert; i++) { - MVert *v = &mvert[unode->index[i]]; + MVert *v = &mvert[unode->index[i].i]; if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) { BLI_BITMAP_FLIP(unode->vert_hidden, i); v->flag ^= ME_HIDE; @@ -330,13 +336,13 @@ static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode) if (unode->maxvert) { /* regular mesh restore */ - int *index = unode->index; + SculptVertRef *index = unode->index; MVert *mvert = ss->mvert; MPropCol *vcol = ss->vcol; for (int i = 0; i < unode->totvert; i++) { - copy_v4_v4(vcol[index[i]].color, unode->col[i]); - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; + swap_v4_v4(vcol[index[i].i].color, unode->col[i]); + mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE; } } return true; @@ -350,7 +356,7 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode) SubdivCCG *subdiv_ccg = ss->subdiv_ccg; MVert *mvert; float *vmask; - int *index; + SculptVertRef *index; if (unode->maxvert) { /* Regular mesh restore. */ @@ -360,9 +366,9 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode) vmask = ss->vmask; for (int i = 0; i < unode->totvert; i++) { - if (vmask[index[i]] != unode->mask[i]) { - SWAP(float, vmask[index[i]], unode->mask[i]); - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; + if (vmask[index[i].i] != unode->mask[i]) { + SWAP(float, vmask[index[i].i], unode->mask[i]); + mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE; } } } @@ -397,7 +403,7 @@ static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode) Mesh *me = BKE_object_get_original_mesh(ob); int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); for (int i = 0; i < me->totpoly; i++) { - face_sets[i] = unode->face_sets[i]; + SWAP(int, face_sets[i], unode->face_sets[i]); } return false; } @@ -410,18 +416,152 @@ static void sculpt_undo_bmesh_restore_generic_task_cb( BKE_pbvh_node_mark_redraw(nodes[n]); } +extern const char dyntopop_node_idx_layer_id[]; + +typedef struct BmeshUndoData { + PBVH *pbvh; + BMesh *bm; + bool do_full_recalc; + bool balance_pbvh; + int cd_face_node_offset, cd_vert_node_offset; +} BmeshUndoData; + +static void bmesh_undo_on_vert_kill(BMVert *v, void *userdata) +{ + BmeshUndoData *data = (BmeshUndoData *)userdata; + // data->do_full_recalc = true; + + if (BM_ELEM_CD_GET_INT(v, data->cd_vert_node_offset) < 0) { + // something went wrong + printf("pbvh bmesh undo error\n"); + data->do_full_recalc = true; + return; + } + else { + int ni = BM_ELEM_CD_GET_INT(v, data->cd_vert_node_offset); + + /* + regenerate bm_unique_verts, which can end up with + freed verts for some reason. I've run this through + ASAN and fixed one likely cause, but it still happens. + - joeedh + */ + if (ni >= 0) { + PBVHNode *node = BKE_pbvh_get_node(data->pbvh, ni); + BKE_pbvh_bmesh_mark_node_regen(data->pbvh, node); + } + } + + BKE_pbvh_bmesh_remove_vertex(data->pbvh, v, false); + data->balance_pbvh = true; +} +static void bmesh_undo_on_vert_add(BMVert *v, void *userdata) +{ + BmeshUndoData *data = (BmeshUndoData *)userdata; + + BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1); + // data->do_full_recalc = true; + data->balance_pbvh = true; +} +static void bmesh_undo_on_face_kill(BMFace *f, void *userdata) +{ + BmeshUndoData *data = (BmeshUndoData *)userdata; + int ni = BM_ELEM_CD_GET_INT(f, data->cd_face_node_offset); + + /* + regenerate bm_unique_verts, which can end up with + freed verts for some reason. I've run this through + ASAN and fixed one likely cause, but it still happens. + - joeedh + */ + if (ni >= 0) { + PBVHNode *node = BKE_pbvh_get_node(data->pbvh, ni); + BKE_pbvh_bmesh_mark_node_regen(data->pbvh, node); + } + + BKE_pbvh_bmesh_remove_face(data->pbvh, f, false); + + // data->do_full_recalc = true; + data->balance_pbvh = true; +} +static void bmesh_undo_on_face_add(BMFace *f, void *userdata) +{ + BmeshUndoData *data = (BmeshUndoData *)userdata; + // data->do_full_recalc = true; + + BM_ELEM_CD_SET_INT(f, data->cd_face_node_offset, -1); + BKE_pbvh_bmesh_add_face(data->pbvh, f, false, true); + + data->balance_pbvh = true; +} +static void bmesh_undo_full_mesh(void *userdata) +{ + BmeshUndoData *data = (BmeshUndoData *)userdata; + data->do_full_recalc = true; +} + +static void bmesh_undo_on_vert_change(BMVert *v, void *userdata, void *old_customdata) +{ + BmeshUndoData *data = (BmeshUndoData *)userdata; + + if (!old_customdata) { + BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1); + return; + } + + BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1); + return; + // preserve pbvh node references + + BMVert h; + h.head.data = old_customdata; + + int oldnode_i = BM_ELEM_CD_GET_INT(&h, data->cd_vert_node_offset); + + BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, oldnode_i); + + if (oldnode_i >= 0) { + PBVHNode *node = BKE_pbvh_node_from_index(data->pbvh, oldnode_i); + BKE_pbvh_node_mark_update(node); + } +} + +static void bmesh_undo_on_face_change(BMFace *f, void *userdata, void *old_customdata) +{ + BmeshUndoData *data = (BmeshUndoData *)userdata; + + // vert will be added back to pbvh when its owning faces are + BM_ELEM_CD_SET_INT(f, data->cd_face_node_offset, -1); +} + static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob, SculptSession *ss) { + BmeshUndoData data = { + ss->pbvh, ss->bm, false, false, ss->cd_face_node_offset, ss->cd_vert_node_offset}; + + BMLogCallbacks callbacks = {bmesh_undo_on_vert_add, + bmesh_undo_on_vert_kill, + bmesh_undo_on_vert_change, + bmesh_undo_on_face_add, + bmesh_undo_on_face_kill, + bmesh_undo_on_face_change, + bmesh_undo_full_mesh, + (void *)&data}; + if (unode->applied) { - BM_log_undo(ss->bm, ss->bm_log); + BM_log_undo(ss->bm, ss->bm_log, &callbacks, dyntopop_node_idx_layer_id); unode->applied = false; } else { - BM_log_redo(ss->bm, ss->bm_log); + BM_log_redo(ss->bm, ss->bm_log, &callbacks, dyntopop_node_idx_layer_id); unode->applied = true; } - if (unode->type == SCULPT_UNDO_MASK) { + BKE_pbvh_bmesh_regen_node_verts(ss->pbvh); + pbvh_bmesh_check_nodes(ss->pbvh); + + if (!data.do_full_recalc || unode->type == SCULPT_UNDO_MASK || + unode->type == SCULPT_UNDO_COLOR) { int totnode; PBVHNode **nodes; @@ -435,6 +575,12 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob, if (nodes) { MEM_freeN(nodes); } + + SCULPT_dyntopo_node_layers_update_offsets(ss); + + if (data.balance_pbvh) { + BKE_pbvh_bmesh_after_stroke(ss->pbvh); + } } else { SCULPT_pbvh_clear(ob); @@ -448,18 +594,27 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode) Mesh *me = ob->data; SCULPT_pbvh_clear(ob); + ss->active_face_index.i = ss->active_vertex_index.i = 0; /* Create empty BMesh and enable logging. */ ss->bm = BM_mesh_create(&bm_mesh_allocsize_default, - &((struct BMeshCreateParams){ - .use_toolflags = false, - })); - BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); + &((struct BMeshCreateParams){.use_toolflags = false, + .use_unique_ids = true, + .use_id_elem_mask = BM_VERT | BM_FACE, + .use_id_map = true})); SCULPT_dyntopo_node_layers_add(ss); + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; - /* Restore the BMLog using saved entries. */ - ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry); + ss->bm_log = BM_log_unfreeze(ss->bm, unode->bm_entry); + + if (!ss->bm_log) { + /* Restore the BMLog using saved entries. */ + ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry); + } + + SCULPT_dyntopo_node_layers_update_offsets(ss); + BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert); } static void sculpt_undo_bmesh_restore_begin(bContext *C, @@ -475,7 +630,7 @@ static void sculpt_undo_bmesh_restore_begin(bContext *C, sculpt_undo_bmesh_enable(ob, unode); /* Restore the mesh from the first log entry. */ - BM_log_redo(ss->bm, ss->bm_log); + BM_log_redo(ss->bm, ss->bm_log, NULL, dyntopop_node_idx_layer_id); unode->applied = true; } @@ -486,11 +641,12 @@ static void sculpt_undo_bmesh_restore_end(bContext *C, Object *ob, SculptSession *ss) { + if (unode->applied) { sculpt_undo_bmesh_enable(ob, unode); /* Restore the mesh from the last log entry. */ - BM_log_undo(ss->bm, ss->bm_log); + BM_log_undo(ss->bm, ss->bm_log, NULL, dyntopop_node_idx_layer_id); unode->applied = false; } @@ -499,6 +655,10 @@ static void sculpt_undo_bmesh_restore_end(bContext *C, SCULPT_dynamic_topology_disable(C, NULL); unode->applied = true; } + + if (ss->bm) { + BM_mesh_elem_index_ensure(ss->bm, BM_VERT); + } } static void sculpt_undo_geometry_store_data(SculptUndoNodeGeometry *geometry, Object *object) @@ -590,23 +750,91 @@ static int sculpt_undo_bmesh_restore(bContext *C, Object *ob, SculptSession *ss) { + if (ss->bm_log && ss->bm && + !ELEM(unode->type, SCULPT_UNDO_DYNTOPO_BEGIN, SCULPT_UNDO_DYNTOPO_END)) { + SCULPT_dyntopo_node_layers_update_offsets(ss); + BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert); + + if (ss->active_face_index.i && ss->active_face_index.i != -1LL) { + ss->active_face_index.i = (intptr_t)BM_log_face_id_get(ss->bm_log, + (BMFace *)ss->active_face_index.i); + } + else { + ss->active_face_index.i = -1; + } + + if (ss->active_vertex_index.i && ss->active_vertex_index.i != -1LL) { + ss->active_vertex_index.i = (intptr_t)BM_log_vert_id_get( + ss->bm_log, (BMVert *)ss->active_vertex_index.i); + } + else { + ss->active_vertex_index.i = -1; + } + } + else { + ss->active_face_index.i = ss->active_vertex_index.i = -1; + } + + bool ret = false; + switch (unode->type) { case SCULPT_UNDO_DYNTOPO_BEGIN: sculpt_undo_bmesh_restore_begin(C, unode, ob, ss); - return true; - + SCULPT_vertex_random_access_ensure(ss); + ss->active_face_index.i = ss->active_vertex_index.i = 0; + ret = true; + break; case SCULPT_UNDO_DYNTOPO_END: - sculpt_undo_bmesh_restore_end(C, unode, ob, ss); - return true; + ss->active_face_index.i = ss->active_vertex_index.i = 0; + + if (ss->bm) { + sculpt_undo_bmesh_restore_end(C, unode, ob, ss); + } + SCULPT_vertex_random_access_ensure(ss); + ret = true; + break; default: if (ss->bm_log) { sculpt_undo_bmesh_restore_generic(unode, ob, ss); - return true; + SCULPT_vertex_random_access_ensure(ss); + ret = true; } break; } - return false; + if (ss->bm_log && ss->bm) { + if (ss->active_face_index.i != -1) { + BMFace *f = BM_log_id_face_get(ss->bm_log, (uint)ss->active_face_index.i); + if (f && f->head.htype == BM_FACE) { + ss->active_face_index.i = (intptr_t)f; + } + else { + ss->active_face_index.i = 0LL; + } + } + else { + ss->active_face_index.i = 0LL; + } + + if (ss->active_vertex_index.i != -1) { + BMVert *v = BM_log_id_vert_get(ss->bm_log, (uint)ss->active_vertex_index.i); + + if (v && v->head.htype == BM_VERT) { + ss->active_vertex_index.i = (intptr_t)v; + } + else { + ss->active_vertex_index.i = 0LL; + } + } + else { + ss->active_vertex_index.i = 0LL; + } + } + else { + ss->active_face_index.i = ss->active_vertex_index.i = 0; + } + + return ret; } /* Geometry updates (such as Apply Base, for example) will re-evaluate the object and refine its @@ -647,8 +875,36 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase bool update = false, rebuild = false, update_mask = false, update_visibility = false; bool need_mask = false; bool need_refine_subdiv = false; + bool did_first_hack = false; for (unode = lb->first; unode; unode = unode->next) { + if (unode->bm_entry && !ss->bm) { + // file loading breaks undo because the stack isn't initialized + // detect that case and try to fix it + + did_first_hack = true; + + ss->active_face_index.i = ss->active_vertex_index.i = 0; + SCULPT_dynamic_topology_enable_ex(CTX_data_main(C), depsgraph, scene, ob); + + // see if we have a saved log in the entry + BMLog *log = BM_log_unfreeze(ss->bm, unode->bm_entry); + + if (log) { + if (ss->bm_log) { + BM_log_free(ss->bm_log, false); + } + + ss->bm_log = log; + + SCULPT_dyntopo_node_layers_update_offsets(ss); + BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert); + } + + // PBVH is corrupted at this point, destroy it + SCULPT_pbvh_clear(ob); + } + /* Restore pivot. */ copy_v3_v3(ss->pivot_pos, unode->pivot_pos); copy_v3_v3(ss->pivot_rot, unode->pivot_rot); @@ -664,7 +920,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); - if (lb->first) { + sculpt_undo_print_nodes(NULL); + + if (!ss->bm && lb->first) { unode = lb->first; if (unode->type == SCULPT_UNDO_FACE_SETS) { sculpt_undo_restore_face_sets(C, unode); @@ -719,6 +977,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase * continue. */ if (unode->maxvert) { if (ss->totvert != unode->maxvert) { + printf("error! %s\n", __func__); continue; } } @@ -859,6 +1118,9 @@ static void sculpt_undo_free_list(ListBase *lb) if (unode->co) { MEM_freeN(unode->co); } + if (unode->nodemap) { + MEM_freeN(unode->nodemap); + } if (unode->no) { MEM_freeN(unode->no); } @@ -888,6 +1150,7 @@ static void sculpt_undo_free_list(ListBase *lb) if (unode->bm_entry) { BM_log_entry_drop(unode->bm_entry); + unode->bm_entry = NULL; } sculpt_undo_geometry_free_data(&unode->geometry_original); @@ -927,7 +1190,28 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb) } #endif -SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node) +static int hash_sculpt_colors(SculptUndoNode *node) +{ + if (!node->col) { + return -1; + } + + int i = 0; + int hash = 0; + + for (i = 0; i < node->totvert; i++) { + float *col = node->col[i]; + + for (int j = 0; j < 4; j++) { + hash = hash ^ (int)(col[j] * 2048.0f * 2048.0f); + hash += (1 << 23) - 1; + } + } + + return hash; +} + +SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node, SculptUndoType type) { UndoSculpt *usculpt = sculpt_undo_get_nodes(); @@ -935,7 +1219,19 @@ SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node) return NULL; } - return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node)); + if (type < 0) { + return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node)); + } + + SculptUndoNode *unode; + + for (unode = usculpt->nodes.first; unode; unode = unode->next) { + if (unode->node == node && type == unode->type) { + return unode; + } + } + + return NULL; } SculptUndoNode *SCULPT_undo_get_first_node() @@ -1104,6 +1400,9 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode) SculptSession *ss = ob->sculpt; PBVHVertexIter vd; + SculptOrigVertData orig_data; + SCULPT_orig_vert_data_unode_init(&orig_data, ob, unode); + BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) { copy_v3_v3(unode->co[vd.i], vd.co); if (vd.no) { @@ -1114,7 +1413,11 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode) } if (ss->deform_modifiers_active) { - copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]); + SCULPT_orig_vert_data_update(&orig_data, &vd); + + int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, unode->index[vd.i]); + + copy_v3_v3(unode->orig_co[vd.i], orig_data.co); } } BKE_pbvh_vertex_iter_end; @@ -1157,6 +1460,8 @@ static void sculpt_undo_store_color(Object *ob, SculptUndoNode *unode) SculptSession *ss = ob->sculpt; PBVHVertexIter vd; + // unode->gen++; + BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) { copy_v4_v4(unode->col[vd.i], vd.col); } @@ -1217,7 +1522,10 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt SculptUndoNode *unode = usculpt->nodes.first; + bool new_node = false; + if (unode == NULL) { + new_node = true; unode = MEM_callocN(sizeof(*unode), __func__); BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname)); @@ -1225,8 +1533,10 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt unode->applied = true; if (type == SCULPT_UNDO_DYNTOPO_END) { - unode->bm_entry = BM_log_entry_add(ss->bm_log); - BM_log_before_all_removed(ss->bm, ss->bm_log); + unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log); + BM_log_full_mesh(ss->bm, ss->bm_log); + + // BM_log_before_all_removed(ss->bm, ss->bm_log); } else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) { /* Store a copy of the mesh's current vertices, loops, and @@ -1237,56 +1547,140 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt SculptUndoNodeGeometry *geometry = &unode->geometry_bmesh_enter; sculpt_undo_geometry_store_data(geometry, ob); - unode->bm_entry = BM_log_entry_add(ss->bm_log); - BM_log_all_added(ss->bm, ss->bm_log); + unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log); + // BM_log_all_added(ss->bm, ss->bm_log); + BM_log_full_mesh(ss->bm, ss->bm_log); } else { - unode->bm_entry = BM_log_entry_add(ss->bm_log); + unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log); } BLI_addtail(&usculpt->nodes, unode); } if (node) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { + unode->bm_entry = BM_log_entry_check_customdata(ss->bm, ss->bm_log); + } + switch (type) { case SCULPT_UNDO_COORDS: case SCULPT_UNDO_MASK: - /* Before any vertex values get modified, ensure their - * original positions are logged. */ - BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { - BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset); + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { + float *dummy; + BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, false); } BKE_pbvh_vertex_iter_end; break; case SCULPT_UNDO_HIDDEN: { - GSetIterator gs_iter; - GSet *faces = BKE_pbvh_bmesh_node_faces(node); - BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { - BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset); + TableGSet *faces = BKE_pbvh_bmesh_node_faces(node); + BMFace *f; + + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { + BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, true); } BKE_pbvh_vertex_iter_end; - GSET_ITER (gs_iter, faces) { - BMFace *f = BLI_gsetIterator_getKey(&gs_iter); + TGSET_ITER (f, faces) { BM_log_face_modified(ss->bm_log, f); } + TGSET_ITER_END + break; + } + + case SCULPT_UNDO_COLOR: { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { + float *dummy; + BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, true); + } + BKE_pbvh_vertex_iter_end; break; } + case SCULPT_UNDO_FACE_SETS: { + TableGSet *faces = BKE_pbvh_bmesh_node_faces(node); + BMFace *f; + TGSET_ITER (f, faces) { + BM_log_face_modified(ss->bm_log, f); + } + TGSET_ITER_END + + break; + } case SCULPT_UNDO_DYNTOPO_BEGIN: case SCULPT_UNDO_DYNTOPO_END: case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: case SCULPT_UNDO_GEOMETRY: - case SCULPT_UNDO_FACE_SETS: - case SCULPT_UNDO_COLOR: break; } } + else { + switch (type) { + case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: + case SCULPT_UNDO_GEOMETRY: + BM_log_full_mesh(ss->bm, ss->bm_log); + break; + } + } + + if (new_node) { + sculpt_undo_print_nodes(NULL); + } return unode; } +bool SCULPT_ensure_dyntopo_node_undo(Object *ob, + PBVHNode *node, + SculptUndoType type, + int extraType) +{ + SculptSession *ss = ob->sculpt; + UndoSculpt *usculpt = sculpt_undo_get_nodes(); + SculptUndoNode *unode = usculpt->nodes.first; + + if (!unode || unode->type != type) { + unode = sculpt_undo_alloc_node_type(ob, type); + + BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname)); + + unode->type = type; + unode->applied = true; + unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log); + + return SCULPT_ensure_dyntopo_node_undo(ob, node, type, extraType); + } + + int n = BKE_pbvh_get_node_id(ss->pbvh, node); + + if (unode->nodemap_size <= n) { + int newsize = (n + 1) * 2; + + if (!unode->nodemap) { + unode->nodemap = MEM_callocN(sizeof(*unode->nodemap) * newsize, "unode->nodemap"); + } + else { + unode->nodemap = MEM_recallocN(unode->nodemap, sizeof(*unode->nodemap) * newsize); + } + + unode->nodemap_size = newsize; + } + + if (unode->nodemap[n]) { + return false; + } + + unode->nodemap[n] = 1; + sculpt_undo_bmesh_push(ob, node, type); + + if (extraType >= 0) { + sculpt_undo_bmesh_push(ob, node, extraType); + } + + return true; +} + SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type) { SculptSession *ss = ob->sculpt; @@ -1301,20 +1695,24 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType /* Dynamic topology stores only one undo node per stroke, * regardless of the number of PBVH nodes modified. */ unode = sculpt_undo_bmesh_push(ob, node, type); + sculpt_undo_print_nodes(NULL); BLI_thread_unlock(LOCK_CUSTOM1); return unode; } if (type == SCULPT_UNDO_GEOMETRY) { unode = sculpt_undo_geometry_push(ob, type); + sculpt_undo_print_nodes(NULL); BLI_thread_unlock(LOCK_CUSTOM1); return unode; } if (type == SCULPT_UNDO_FACE_SETS) { unode = sculpt_undo_face_sets_push(ob, type); + sculpt_undo_print_nodes(NULL); BLI_thread_unlock(LOCK_CUSTOM1); return unode; } - if ((unode = SCULPT_undo_get_node(node))) { + if ((unode = SCULPT_undo_get_node(node, type))) { + sculpt_undo_print_nodes(NULL); BLI_thread_unlock(LOCK_CUSTOM1); return unode; } @@ -1336,7 +1734,11 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType int allvert; BKE_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert); BKE_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL); - memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert); + + for (int i = 0; i < unode->totvert; i++) { + unode->index[i].i = vert_indices[i]; + } + // memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert); } switch (type) { @@ -1373,6 +1775,8 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType unode->shapeName[0] = '\0'; } + sculpt_undo_print_nodes(NULL); + BLI_thread_unlock(LOCK_CUSTOM1); return unode; @@ -1434,6 +1838,7 @@ typedef struct SculptUndoStep { UndoStep step; /* NOTE: will split out into list for multi-object-sculpt-mode. */ UndoSculpt data; + int id; } SculptUndoStep; static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p) @@ -1472,6 +1877,8 @@ static void sculpt_undosys_step_decode_undo_impl(struct bContext *C, BLI_assert(us->step.is_applied == true); sculpt_undo_restore_list(C, depsgraph, &us->data.nodes); us->step.is_applied = false; + + sculpt_undo_print_nodes(us); } static void sculpt_undosys_step_decode_redo_impl(struct bContext *C, @@ -1481,6 +1888,8 @@ static void sculpt_undosys_step_decode_redo_impl(struct bContext *C, BLI_assert(us->step.is_applied == false); sculpt_undo_restore_list(C, depsgraph, &us->data.nodes); us->step.is_applied = true; + + sculpt_undo_print_nodes(us); } static void sculpt_undosys_step_decode_undo(struct bContext *C, @@ -1632,6 +2041,10 @@ static UndoSculpt *sculpt_undo_get_nodes(void) return sculpt_undosys_step_get_nodes(us); } +void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss) +{ +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1726,3 +2139,106 @@ void ED_sculpt_undo_push_multires_mesh_end(bContext *C, const char *str) } /** \} */ + +#ifdef _ +# undef _ +#endif +#define _(type) \ + case type: \ + return #type; +static char *undo_type_to_str(int type) +{ + switch (type) { + _(SCULPT_UNDO_DYNTOPO_BEGIN) + _(SCULPT_UNDO_DYNTOPO_END) + _(SCULPT_UNDO_COORDS) + _(SCULPT_UNDO_GEOMETRY) + _(SCULPT_UNDO_DYNTOPO_SYMMETRIZE) + _(SCULPT_UNDO_FACE_SETS) + _(SCULPT_UNDO_HIDDEN) + _(SCULPT_UNDO_MASK) + _(SCULPT_UNDO_COLOR) + default: + return "unknown node type"; + } +} +#undef _ + +static int nodeidgen = 1; + +static void print_sculpt_node(SculptUndoNode *node) +{ + int hash = hash_sculpt_colors(node); + + // if (node->lasthash == 0) { + // node->lasthash = hash; + // } + + printf(" %s:%s {applied=%d gen=%d hash=%d}\n", + undo_type_to_str(node->type), + node->idname, + node->applied, + 0, // node->gen, + hash /*- node->lasthash*/); +} + +static void print_sculpt_undo_step(UndoStep *us, UndoStep *active, int i) +{ + SculptUndoNode *node; + + if (us->type != BKE_UNDOSYS_TYPE_SCULPT) { + return; + } + + int id = -1; + + SculptUndoStep *su = (SculptUndoStep *)us; + if (!su->id) { + su->id = nodeidgen++; + } + + id = su->id; + + printf("id=%d %s %d %s\n", id, us == active ? "->" : " ", i, us->name); + + if (us->type == BKE_UNDOSYS_TYPE_SCULPT) { + UndoSculpt *usculpt = sculpt_undosys_step_get_nodes(us); + + for (node = usculpt->nodes.first; node; node = node->next) { + print_sculpt_node(node); + } + } +} +void sculpt_undo_print_nodes(void *active) +{ +#if 0 + UndoStack *ustack = ED_undo_stack_get(); + UndoStep *us = ustack->steps.first; + if (active == NULL) { + active = ustack->step_active; + } + + SculptUndoNode *node; + + if (!us) { + return; + } + + printf("\n"); + if (ustack->step_init) { + printf("===undo init===\n"); + print_sculpt_undo_step(ustack->step_init, active, -1); + printf("===============\n"); + } + + int i = 0; + for (; us; us = us->next, i++) { + print_sculpt_undo_step(us, active, i); + } + + if (ustack->step_active) { + print_sculpt_undo_step(ustack->step_active, active, i); + } + +#endif +} |