Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt_undo.c
| Show First 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | static void update_cb(PBVHNode *node, void *rebuild) | ||||
| } | } | ||||
| BKE_pbvh_node_fully_hidden_set(node, 0); | BKE_pbvh_node_fully_hidden_set(node, 0); | ||||
| } | } | ||||
| struct PartialUpdateData { | struct PartialUpdateData { | ||||
| PBVH *pbvh; | PBVH *pbvh; | ||||
| bool rebuild; | bool rebuild; | ||||
| char *modified_grids; | char *modified_grids; | ||||
| bool *modified_hidden_vertices; | |||||
| bool *modified_mask_vertices; | |||||
| bool *modified_color_vertices; | |||||
| }; | }; | ||||
| /** | /** | ||||
| * A version of #update_cb that tests for the update tag in #PBVH.vert_bitmap. | * A version of #update_cb that tests for the update tag in #PBVH.vert_bitmap. | ||||
| */ | */ | ||||
| static void update_cb_partial(PBVHNode *node, void *userdata) | static void update_cb_partial(PBVHNode *node, void *userdata) | ||||
| { | { | ||||
| struct PartialUpdateData *data = userdata; | struct PartialUpdateData *data = userdata; | ||||
| if (BKE_pbvh_type(data->pbvh) == PBVH_GRIDS) { | if (BKE_pbvh_type(data->pbvh) == PBVH_GRIDS) { | ||||
| int *node_grid_indices; | int *node_grid_indices; | ||||
| int totgrid; | int totgrid; | ||||
| bool update = false; | bool update = false; | ||||
| BKE_pbvh_node_get_grids(data->pbvh, node, &node_grid_indices, &totgrid, NULL, NULL, NULL); | BKE_pbvh_node_get_grids(data->pbvh, node, &node_grid_indices, &totgrid, NULL, NULL, NULL); | ||||
| for (int i = 0; i < totgrid; i++) { | for (int i = 0; i < totgrid; i++) { | ||||
| if (data->modified_grids[node_grid_indices[i]] == 1) { | if (data->modified_grids[node_grid_indices[i]] == 1) { | ||||
| update = true; | update = true; | ||||
| } | } | ||||
| } | } | ||||
| if (update) { | if (update) { | ||||
| update_cb(node, &(data->rebuild)); | update_cb(node, &(data->rebuild)); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) { | if (BKE_pbvh_node_has_vert_with_normal_update_tag(data->pbvh, node)) { | ||||
| update_cb(node, &(data->rebuild)); | BKE_pbvh_node_mark_normals_update(node); | ||||
| } | |||||
| int verts_num; | |||||
| const int *vert_indices; | |||||
| BKE_pbvh_node_num_verts(data->pbvh, node, NULL, &verts_num); | |||||
| BKE_pbvh_node_get_verts(data->pbvh, node, &vert_indices, NULL); | |||||
| if (data->modified_mask_vertices != NULL) { | |||||
| for (int i = 0; i < verts_num; i++) { | |||||
| if (data->modified_mask_vertices[vert_indices[i]]) { | |||||
| BKE_pbvh_node_mark_update_mask(node); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (data->modified_color_vertices != NULL) { | |||||
| for (int i = 0; i < verts_num; i++) { | |||||
| if (data->modified_color_vertices[vert_indices[i]]) { | |||||
| BKE_pbvh_node_mark_update_color(node); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (data->modified_hidden_vertices != NULL) { | |||||
| for (int i = 0; i < verts_num; i++) { | |||||
| if (data->modified_hidden_vertices[vert_indices[i]]) { | |||||
| if (data->rebuild) { | |||||
| BKE_pbvh_node_mark_update_visibility(node); | |||||
| } | |||||
| BKE_pbvh_node_fully_hidden_set(node, 0); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static bool test_swap_v3_v3(float a[3], float b[3]) | static bool test_swap_v3_v3(float a[3], float b[3]) | ||||
| { | { | ||||
| /* No need for float comparison here (memory is exactly equal or not). */ | /* No need for float comparison here (memory is exactly equal or not). */ | ||||
| if (memcmp(a, b, sizeof(float[3])) != 0) { | if (memcmp(a, b, sizeof(float[3])) != 0) { | ||||
| ▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | if (ss->shapekey_active) { | ||||
| MEM_freeN(vertCos); | MEM_freeN(vertCos); | ||||
| } | } | ||||
| else { | else { | ||||
| if (unode->orig_co) { | if (unode->orig_co) { | ||||
| if (ss->deform_modifiers_active) { | if (ss->deform_modifiers_active) { | ||||
| for (int i = 0; i < unode->totvert; i++) { | for (int i = 0; i < unode->totvert; i++) { | ||||
| sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co); | sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co); | ||||
| BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_make_vref(index[i])); | BKE_pbvh_vert_tag_update_normal(ss->pbvh, BKE_pbvh_make_vref(index[i])); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| for (int i = 0; i < unode->totvert; i++) { | for (int i = 0; i < unode->totvert; i++) { | ||||
| swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]); | swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]); | ||||
| BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_make_vref(index[i])); | BKE_pbvh_vert_tag_update_normal(ss->pbvh, BKE_pbvh_make_vref(index[i])); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| for (int i = 0; i < unode->totvert; i++) { | for (int i = 0; i < unode->totvert; i++) { | ||||
| swap_v3_v3(mvert[index[i]].co, unode->co[i]); | swap_v3_v3(mvert[index[i]].co, unode->co[i]); | ||||
| BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_make_vref(index[i])); | BKE_pbvh_vert_tag_update_normal(ss->pbvh, BKE_pbvh_make_vref(index[i])); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (unode->maxgrid && subdiv_ccg != NULL) { | else if (unode->maxgrid && subdiv_ccg != NULL) { | ||||
| /* Multires restore. */ | /* Multires restore. */ | ||||
| CCGElem **grids, *grid; | CCGElem **grids, *grid; | ||||
| CCGKey key; | CCGKey key; | ||||
| Show All 12 Lines | for (int j = 0; j < unode->totgrid; j++) { | ||||
| swap_v3_v3(CCG_elem_offset_co(&key, grid, i), co[0]); | swap_v3_v3(CCG_elem_offset_co(&key, grid, i), co[0]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode) | static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode, bool *modified_vertices) | ||||
| { | { | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| Object *ob = OBACT(view_layer); | Object *ob = OBACT(view_layer); | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| SubdivCCG *subdiv_ccg = ss->subdiv_ccg; | SubdivCCG *subdiv_ccg = ss->subdiv_ccg; | ||||
| if (unode->maxvert) { | if (unode->maxvert) { | ||||
| MVert *mvert = ss->mvert; | MVert *mvert = ss->mvert; | ||||
| for (int i = 0; i < unode->totvert; i++) { | for (int i = 0; i < unode->totvert; i++) { | ||||
| MVert *v = &mvert[unode->index[i]]; | MVert *v = &mvert[unode->index[i]]; | ||||
| if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) { | if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) { | ||||
| BLI_BITMAP_FLIP(unode->vert_hidden, i); | BLI_BITMAP_FLIP(unode->vert_hidden, i); | ||||
| v->flag ^= ME_HIDE; | v->flag ^= ME_HIDE; | ||||
| BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_make_vref(unode->index[i])); | modified_vertices[unode->index[i]] = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (unode->maxgrid && subdiv_ccg != NULL) { | else if (unode->maxgrid && subdiv_ccg != NULL) { | ||||
| BLI_bitmap **grid_hidden = subdiv_ccg->grid_hidden; | BLI_bitmap **grid_hidden = subdiv_ccg->grid_hidden; | ||||
| for (int i = 0; i < unode->totgrid; i++) { | for (int i = 0; i < unode->totgrid; i++) { | ||||
| SWAP(BLI_bitmap *, unode->grid_hidden[i], grid_hidden[unode->grids[i]]); | SWAP(BLI_bitmap *, unode->grid_hidden[i], grid_hidden[unode->grids[i]]); | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode) | static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode, bool *modified_vertices) | ||||
| { | { | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| Object *ob = OBACT(view_layer); | Object *ob = OBACT(view_layer); | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| bool modified = false; | bool modified = false; | ||||
| /* NOTE: even with loop colors we still store derived | /* NOTE: even with loop colors we still store derived | ||||
| * vertex colors for original data lookup. */ | * vertex colors for original data lookup. */ | ||||
| if (unode->col && !unode->loop_col) { | if (unode->col && !unode->loop_col) { | ||||
| BKE_pbvh_swap_colors(ss->pbvh, unode->index, unode->totvert, unode->col); | BKE_pbvh_swap_colors(ss->pbvh, unode->index, unode->totvert, unode->col); | ||||
| modified = true; | modified = true; | ||||
| } | } | ||||
| Mesh *me = BKE_object_get_original_mesh(ob); | Mesh *me = BKE_object_get_original_mesh(ob); | ||||
| if (unode->loop_col && unode->maxloop == me->totloop) { | if (unode->loop_col && unode->maxloop == me->totloop) { | ||||
| BKE_pbvh_swap_colors(ss->pbvh, unode->loop_index, unode->totloop, unode->loop_col); | BKE_pbvh_swap_colors(ss->pbvh, unode->loop_index, unode->totloop, unode->loop_col); | ||||
| modified = true; | modified = true; | ||||
| } | } | ||||
| if (modified) { | if (modified) { | ||||
| for (int i = 0; i < unode->totvert; i++) { | for (int i = 0; i < unode->totvert; i++) { | ||||
| BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_index_to_vertex(ss->pbvh, unode->index[i])); | modified_vertices[unode->index[i]] = true; | ||||
| } | } | ||||
| } | } | ||||
| return modified; | return modified; | ||||
| } | } | ||||
| static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode) | static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode, bool *modified_vertices) | ||||
| { | { | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| Object *ob = OBACT(view_layer); | Object *ob = OBACT(view_layer); | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| SubdivCCG *subdiv_ccg = ss->subdiv_ccg; | SubdivCCG *subdiv_ccg = ss->subdiv_ccg; | ||||
| float *vmask; | float *vmask; | ||||
| int *index; | int *index; | ||||
| if (unode->maxvert) { | if (unode->maxvert) { | ||||
| /* Regular mesh restore. */ | /* Regular mesh restore. */ | ||||
| index = unode->index; | index = unode->index; | ||||
| vmask = ss->vmask; | vmask = ss->vmask; | ||||
| for (int i = 0; i < unode->totvert; i++) { | for (int i = 0; i < unode->totvert; i++) { | ||||
| if (vmask[index[i]] != unode->mask[i]) { | if (vmask[index[i]] != unode->mask[i]) { | ||||
| SWAP(float, vmask[index[i]], unode->mask[i]); | SWAP(float, vmask[index[i]], unode->mask[i]); | ||||
| BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_make_vref(index[i])); | modified_vertices[index[i]] = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (unode->maxgrid && subdiv_ccg != NULL) { | else if (unode->maxgrid && subdiv_ccg != NULL) { | ||||
| /* Multires restore. */ | /* Multires restore. */ | ||||
| CCGElem **grids, *grid; | CCGElem **grids, *grid; | ||||
| CCGKey key; | CCGKey key; | ||||
| float *mask; | float *mask; | ||||
| ▲ Show 20 Lines • Show All 329 Lines • ▼ Show 20 Lines | if (first_unode->type != SCULPT_UNDO_GEOMETRY) { | ||||
| BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask, false); | BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask, false); | ||||
| } | } | ||||
| if (sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) { | if (sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) { | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| /* The PBVH already keeps track of which vertices need updated normals, but it doesn't keep track | |||||
| * of other updated. In order to tell the corresponding PBVH nodes to update, keep track of which | |||||
| * elements were updated for specific layers. */ | |||||
| bool *modified_hidden_vertices = NULL; | |||||
| bool *modified_mask_vertices = NULL; | |||||
| bool *modified_color_vertices = NULL; | |||||
| char *undo_modified_grids = NULL; | char *undo_modified_grids = NULL; | ||||
| bool use_multires_undo = false; | bool use_multires_undo = false; | ||||
| for (unode = lb->first; unode; unode = unode->next) { | for (unode = lb->first; unode; unode = unode->next) { | ||||
| if (!STREQ(unode->idname, ob->id.name)) { | if (!STREQ(unode->idname, ob->id.name)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| Show All 16 Lines | for (unode = lb->first; unode; unode = unode->next) { | ||||
| switch (unode->type) { | switch (unode->type) { | ||||
| case SCULPT_UNDO_COORDS: | case SCULPT_UNDO_COORDS: | ||||
| if (sculpt_undo_restore_coords(C, depsgraph, unode)) { | if (sculpt_undo_restore_coords(C, depsgraph, unode)) { | ||||
| update = true; | update = true; | ||||
| } | } | ||||
| break; | break; | ||||
| case SCULPT_UNDO_HIDDEN: | case SCULPT_UNDO_HIDDEN: | ||||
| if (sculpt_undo_restore_hidden(C, unode)) { | if (modified_hidden_vertices == NULL) { | ||||
| modified_hidden_vertices = MEM_calloc_arrayN(ss->totvert, sizeof(bool), __func__); | |||||
| } | |||||
| if (sculpt_undo_restore_hidden(C, unode, modified_hidden_vertices)) { | |||||
| rebuild = true; | rebuild = true; | ||||
| update_visibility = true; | update_visibility = true; | ||||
| } | } | ||||
| break; | break; | ||||
| case SCULPT_UNDO_MASK: | case SCULPT_UNDO_MASK: | ||||
| if (sculpt_undo_restore_mask(C, unode)) { | if (modified_mask_vertices == NULL) { | ||||
| modified_mask_vertices = MEM_calloc_arrayN(ss->totvert, sizeof(bool), __func__); | |||||
| } | |||||
| if (sculpt_undo_restore_mask(C, unode, modified_mask_vertices)) { | |||||
| update = true; | update = true; | ||||
| update_mask = true; | update_mask = true; | ||||
| } | } | ||||
| break; | break; | ||||
| case SCULPT_UNDO_FACE_SETS: | case SCULPT_UNDO_FACE_SETS: | ||||
| break; | break; | ||||
| case SCULPT_UNDO_COLOR: | case SCULPT_UNDO_COLOR: | ||||
| if (sculpt_undo_restore_color(C, unode)) { | if (modified_color_vertices == NULL) { | ||||
| modified_color_vertices = MEM_calloc_arrayN(ss->totvert, sizeof(bool), __func__); | |||||
| } | |||||
| if (sculpt_undo_restore_color(C, unode, modified_color_vertices)) { | |||||
| update = true; | update = true; | ||||
| } | } | ||||
| break; | break; | ||||
| case SCULPT_UNDO_GEOMETRY: | case SCULPT_UNDO_GEOMETRY: | ||||
| need_refine_subdiv = true; | need_refine_subdiv = true; | ||||
| sculpt_undo_geometry_restore(unode, ob); | sculpt_undo_geometry_restore(unode, ob); | ||||
| BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask, false); | BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask, false); | ||||
| Show All 34 Lines | if (update || rebuild) { | ||||
| bool tag_update = false; | bool tag_update = false; | ||||
| /* We update all nodes still, should be more clever, but also | /* We update all nodes still, should be more clever, but also | ||||
| * needs to work correct when exiting/entering sculpt mode and | * needs to work correct when exiting/entering sculpt mode and | ||||
| * the nodes get recreated, though in that case it could do all. */ | * the nodes get recreated, though in that case it could do all. */ | ||||
| struct PartialUpdateData data = { | struct PartialUpdateData data = { | ||||
| .rebuild = rebuild, | .rebuild = rebuild, | ||||
| .pbvh = ss->pbvh, | .pbvh = ss->pbvh, | ||||
| .modified_grids = undo_modified_grids, | .modified_grids = undo_modified_grids, | ||||
| .modified_hidden_vertices = modified_hidden_vertices, | |||||
| .modified_mask_vertices = modified_mask_vertices, | |||||
| .modified_color_vertices = modified_color_vertices, | |||||
| }; | }; | ||||
| BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data); | BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data); | ||||
| BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw); | BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw); | ||||
| if (update_mask) { | if (update_mask) { | ||||
| BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); | BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); | ||||
| } | } | ||||
| Show All 30 Lines | if (tag_update) { | ||||
| DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); | DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); | ||||
| } | } | ||||
| else { | else { | ||||
| SCULPT_update_object_bounding_box(ob); | SCULPT_update_object_bounding_box(ob); | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(undo_modified_grids); | MEM_SAFE_FREE(undo_modified_grids); | ||||
| MEM_SAFE_FREE(modified_hidden_vertices); | |||||
| MEM_SAFE_FREE(modified_mask_vertices); | |||||
| MEM_SAFE_FREE(modified_color_vertices); | |||||
| } | } | ||||
| static void sculpt_undo_free_list(ListBase *lb) | static void sculpt_undo_free_list(ListBase *lb) | ||||
| { | { | ||||
| SculptUndoNode *unode = lb->first; | SculptUndoNode *unode = lb->first; | ||||
| while (unode != NULL) { | while (unode != NULL) { | ||||
| SculptUndoNode *unode_next = unode->next; | SculptUndoNode *unode_next = unode->next; | ||||
| if (unode->co) { | if (unode->co) { | ||||
| ▲ Show 20 Lines • Show All 974 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| SculptSession *ss = object->sculpt; | SculptSession *ss = object->sculpt; | ||||
| /* It is possible that undo push is done from an object state where there is no PBVH. This | /* It is possible that undo push is done from an object state where there is no PBVH. This | ||||
| * happens, for example, when an operation which tagged for geometry update was performed prior | * happens, for example, when an operation which tagged for geometry update was performed prior | ||||
| * to the current operation without making any stroke in between. | * to the current operation without making any stroke in between. | ||||
| * | * | ||||
| * Skip pushing nodes based on the following logic: on redo SCULPT_UNDO_COORDS will ensure | * Skip pushing nodes based on the following logic: on redo SCULPT_UNDO_COORDS will ensure | ||||
| * PBVH for the new base geometry, which will have same coordinates as if we create PBVH here. */ | * PBVH for the new base geometry, which will have same coordinates as if we create PBVH here. | ||||
| */ | |||||
| if (ss->pbvh == NULL) { | if (ss->pbvh == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| PBVHNode **nodes; | PBVHNode **nodes; | ||||
| int totnodes; | int totnodes; | ||||
| BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes); | BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes); | ||||
| Show All 40 Lines | |||||