Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt_undo.c
| Show First 20 Lines • Show All 286 Lines • ▼ Show 20 Lines | |||||
| struct PartialUpdateData { | struct PartialUpdateData { | ||||
| PBVH *pbvh; | PBVH *pbvh; | ||||
| bool rebuild; | bool rebuild; | ||||
| char *modified_grids; | char *modified_grids; | ||||
| bool *modified_hidden_verts; | bool *modified_hidden_verts; | ||||
| bool *modified_mask_verts; | bool *modified_mask_verts; | ||||
| bool *modified_color_verts; | bool *modified_color_verts; | ||||
| bool *modified_face_set_faces; | |||||
| }; | }; | ||||
| /** | /** | ||||
| * 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; | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | if (data->modified_hidden_verts != NULL) { | ||||
| BKE_pbvh_node_mark_update_visibility(node); | BKE_pbvh_node_mark_update_visibility(node); | ||||
| } | } | ||||
| BKE_pbvh_node_fully_hidden_set(node, 0); | BKE_pbvh_node_fully_hidden_set(node, 0); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (data->modified_face_set_faces) { | |||||
| PBVHFaceIter fd; | |||||
| BKE_pbvh_face_iter_begin (data->pbvh, node, fd) { | |||||
| if (data->modified_face_set_faces[fd.index]) { | |||||
| BKE_pbvh_node_mark_update_face_sets(node); | |||||
| break; | |||||
| } | |||||
| } | |||||
| BKE_pbvh_face_iter_end(fd); | |||||
| } | |||||
| } | } | ||||
| 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) { | ||||
| swap_v3_v3(a, b); | swap_v3_v3(a, b); | ||||
| return true; | return true; | ||||
| ▲ Show 20 Lines • Show All 234 Lines • ▼ Show 20 Lines | for (int j = 0; j < unode->totgrid; j++) { | ||||
| SWAP(float, *CCG_elem_offset_mask(&key, grid, i), *mask); | SWAP(float, *CCG_elem_offset_mask(&key, grid, i), *mask); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode) | static bool sculpt_undo_restore_face_sets(bContext *C, | ||||
| SculptUndoNode *unode, | |||||
| bool *modified_face_set_faces) | |||||
| { | { | ||||
| const Scene *scene = CTX_data_scene(C); | const Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| BKE_view_layer_synced_ensure(scene, view_layer); | BKE_view_layer_synced_ensure(scene, view_layer); | ||||
| Object *ob = BKE_view_layer_active_object_get(view_layer); | Object *ob = BKE_view_layer_active_object_get(view_layer); | ||||
| Mesh *me = BKE_object_get_original_mesh(ob); | Mesh *me = BKE_object_get_original_mesh(ob); | ||||
| SculptSession *ss = ob->sculpt; | |||||
| int *face_sets = CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, ".sculpt_face_set"); | ss->face_sets = BKE_sculpt_face_sets_ensure(me); | ||||
| if (!face_sets) { | BKE_pbvh_face_sets_set(ss->pbvh, ss->face_sets); | ||||
| face_sets = CustomData_add_layer_named( | |||||
| &me->pdata, CD_PROP_INT32, CD_CONSTRUCT, NULL, me->totpoly, ".sculpt_face_set"); | bool modified = false; | ||||
| } | |||||
| for (int i = 0; i < me->totpoly; i++) { | for (int i = 0; i < unode->faces_num; i++) { | ||||
| SWAP(int, face_sets[i], unode->face_sets[i]); | int face_index = unode->faces[i].i; | ||||
| SWAP(int, unode->face_sets[i], ss->face_sets[face_index]); | |||||
| modified_face_set_faces[face_index] = unode->face_sets[i] != ss->face_sets[face_index]; | |||||
| modified |= modified_face_set_faces[face_index]; | |||||
| } | } | ||||
| return false; | |||||
| return modified; | |||||
| } | } | ||||
| static void sculpt_undo_bmesh_restore_generic_task_cb( | static void sculpt_undo_bmesh_restore_generic_task_cb( | ||||
| void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) | void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) | ||||
| { | { | ||||
| PBVHNode **nodes = userdata; | PBVHNode **nodes = userdata; | ||||
| BKE_pbvh_node_mark_redraw(nodes[n]); | BKE_pbvh_node_mark_redraw(nodes[n]); | ||||
| ▲ Show 20 Lines • Show All 230 Lines • ▼ Show 20 Lines | static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase *lb) | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| RegionView3D *rv3d = CTX_wm_region_view3d(C); | RegionView3D *rv3d = CTX_wm_region_view3d(C); | ||||
| BKE_view_layer_synced_ensure(scene, view_layer); | BKE_view_layer_synced_ensure(scene, view_layer); | ||||
| Object *ob = BKE_view_layer_active_object_get(view_layer); | Object *ob = BKE_view_layer_active_object_get(view_layer); | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| SubdivCCG *subdiv_ccg = ss->subdiv_ccg; | SubdivCCG *subdiv_ccg = ss->subdiv_ccg; | ||||
| SculptUndoNode *unode; | SculptUndoNode *unode; | ||||
| bool update = false, rebuild = false, update_mask = false, update_visibility = false; | bool update = false, rebuild = false, update_mask = false, update_visibility = false; | ||||
| bool update_face_sets = false; | |||||
| bool need_mask = false; | bool need_mask = false; | ||||
| bool need_refine_subdiv = false; | bool need_refine_subdiv = false; | ||||
| bool clear_automask_cache = false; | bool clear_automask_cache = false; | ||||
| for (unode = lb->first; unode; unode = unode->next) { | for (unode = lb->first; unode; unode = unode->next) { | ||||
| if (!ELEM(unode->type, SCULPT_UNDO_COLOR, SCULPT_UNDO_MASK)) { | if (!ELEM(unode->type, SCULPT_UNDO_COLOR, SCULPT_UNDO_MASK)) { | ||||
| clear_automask_cache = true; | clear_automask_cache = true; | ||||
| } | } | ||||
| Show All 12 Lines | static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase *lb) | ||||
| } | } | ||||
| if (clear_automask_cache) { | if (clear_automask_cache) { | ||||
| ss->last_automasking_settings_hash = 0; | ss->last_automasking_settings_hash = 0; | ||||
| } | } | ||||
| DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); | DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); | ||||
| if (lb->first) { | |||||
| unode = lb->first; | |||||
| if (unode->type == SCULPT_UNDO_FACE_SETS) { | |||||
| sculpt_undo_restore_face_sets(C, unode); | |||||
| rebuild = true; | |||||
| BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild); | |||||
| BKE_sculpt_update_object_for_edit(depsgraph, ob, true, need_mask, false); | |||||
| SCULPT_visibility_sync_all_from_faces(ob); | |||||
| BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility); | |||||
| if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { | |||||
| BKE_mesh_flush_hidden_from_verts(ob->data); | |||||
| } | |||||
| DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); | |||||
| if (!BKE_sculptsession_use_pbvh_draw(ob, rv3d)) { | |||||
| DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); | |||||
| } | |||||
| unode->applied = true; | |||||
| return; | |||||
| } | |||||
| } | |||||
| if (lb->first != NULL) { | if (lb->first != NULL) { | ||||
| /* Only do early object update for edits if first node needs this. | /* Only do early object update for edits if first node needs this. | ||||
| * Undo steps like geometry does not need object to be updated before they run and will | * Undo steps like geometry does not need object to be updated before they run and will | ||||
| * ensure object is updated after the node is handled. */ | * ensure object is updated after the node is handled. */ | ||||
| const SculptUndoNode *first_unode = (const SculptUndoNode *)lb->first; | const SculptUndoNode *first_unode = (const SculptUndoNode *)lb->first; | ||||
| if (first_unode->type != SCULPT_UNDO_GEOMETRY) { | 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 | /* The PBVH already keeps track of which vertices need updated normals, but it doesn't keep | ||||
| * of other updated. In order to tell the corresponding PBVH nodes to update, keep track of which | * track of other updated. In order to tell the corresponding PBVH nodes to update, keep track | ||||
| * elements were updated for specific layers. */ | * of which elements were updated for specific layers. */ | ||||
HooglyBoogly: Unnecessary change here | |||||
| bool *modified_hidden_verts = NULL; | bool *modified_hidden_verts = NULL; | ||||
| bool *modified_mask_verts = NULL; | bool *modified_mask_verts = NULL; | ||||
| bool *modified_color_verts = NULL; | bool *modified_color_verts = NULL; | ||||
| bool *modified_face_set_faces = 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 34 Lines | switch (unode->type) { | ||||
| modified_mask_verts = MEM_calloc_arrayN(ss->totvert, sizeof(bool), __func__); | modified_mask_verts = MEM_calloc_arrayN(ss->totvert, sizeof(bool), __func__); | ||||
| } | } | ||||
| if (sculpt_undo_restore_mask(C, unode, modified_mask_verts)) { | if (sculpt_undo_restore_mask(C, unode, modified_mask_verts)) { | ||||
| update = true; | update = true; | ||||
| update_mask = true; | update_mask = true; | ||||
| } | } | ||||
| break; | break; | ||||
| case SCULPT_UNDO_FACE_SETS: | case SCULPT_UNDO_FACE_SETS: | ||||
| if (modified_face_set_faces == NULL) { | |||||
| modified_face_set_faces = MEM_calloc_arrayN( | |||||
| BKE_pbvh_num_faces(ss->pbvh), sizeof(bool), __func__); | |||||
| } | |||||
| if (sculpt_undo_restore_face_sets(C, unode, modified_face_set_faces)) { | |||||
| update = true; | |||||
| update_face_sets = true; | |||||
| } | |||||
| break; | break; | ||||
| case SCULPT_UNDO_COLOR: | case SCULPT_UNDO_COLOR: | ||||
| if (modified_color_verts == NULL) { | if (modified_color_verts == NULL) { | ||||
| modified_color_verts = MEM_calloc_arrayN(ss->totvert, sizeof(bool), __func__); | modified_color_verts = MEM_calloc_arrayN(ss->totvert, sizeof(bool), __func__); | ||||
| } | } | ||||
| if (sculpt_undo_restore_color(C, unode, modified_color_verts)) { | if (sculpt_undo_restore_color(C, unode, modified_color_verts)) { | ||||
| update = true; | update = true; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (update || rebuild) { | ||||
| * 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_verts = modified_hidden_verts, | .modified_hidden_verts = modified_hidden_verts, | ||||
| .modified_mask_verts = modified_mask_verts, | .modified_mask_verts = modified_mask_verts, | ||||
| .modified_color_verts = modified_color_verts, | .modified_color_verts = modified_color_verts, | ||||
| .modified_face_set_faces = modified_face_set_faces, | |||||
| }; | }; | ||||
Done Inline ActionsUnnecessary newline here HooglyBoogly: Unnecessary newline here | |||||
| 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); | ||||
| } | } | ||||
| if (update_face_sets) { | |||||
| DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); | |||||
| BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_RebuildDrawBuffers); | |||||
| } | |||||
| if (update_visibility) { | if (update_visibility) { | ||||
| if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_GRIDS)) { | if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_GRIDS)) { | ||||
| Mesh *me = (Mesh *)ob->data; | Mesh *me = (Mesh *)ob->data; | ||||
| BKE_pbvh_sync_visibility_from_verts(ss->pbvh, me); | BKE_pbvh_sync_visibility_from_verts(ss->pbvh, me); | ||||
| BKE_pbvh_update_hide_attributes_from_mesh(ss->pbvh); | BKE_pbvh_update_hide_attributes_from_mesh(ss->pbvh); | ||||
| } | } | ||||
| Show All 26 Lines | if (update || rebuild) { | ||||
| else { | else { | ||||
| SCULPT_update_object_bounding_box(ob); | SCULPT_update_object_bounding_box(ob); | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(modified_hidden_verts); | MEM_SAFE_FREE(modified_hidden_verts); | ||||
| MEM_SAFE_FREE(modified_mask_verts); | MEM_SAFE_FREE(modified_mask_verts); | ||||
| MEM_SAFE_FREE(modified_color_verts); | MEM_SAFE_FREE(modified_color_verts); | ||||
| MEM_SAFE_FREE(modified_face_set_faces); | |||||
| MEM_SAFE_FREE(undo_modified_grids); | MEM_SAFE_FREE(undo_modified_grids); | ||||
| } | } | ||||
| 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) { | ||||
| MEM_freeN(unode->co); | MEM_freeN(unode->co); | ||||
| } | } | ||||
| if (unode->col) { | if (unode->col) { | ||||
| MEM_freeN(unode->col); | MEM_freeN(unode->col); | ||||
| } | } | ||||
| if (unode->loop_col) { | if (unode->loop_col) { | ||||
| MEM_freeN(unode->loop_col); | MEM_freeN(unode->loop_col); | ||||
| } | } | ||||
| if (unode->no) { | if (unode->no) { | ||||
| MEM_freeN(unode->no); | MEM_freeN(unode->no); | ||||
| } | } | ||||
| if (unode->index) { | if (unode->index) { | ||||
| MEM_freeN(unode->index); | MEM_freeN(unode->index); | ||||
| } | } | ||||
| if (unode->faces) { | |||||
| MEM_freeN(unode->faces); | |||||
| } | |||||
| if (unode->loop_index) { | if (unode->loop_index) { | ||||
| MEM_freeN(unode->loop_index); | MEM_freeN(unode->loop_index); | ||||
| } | } | ||||
| if (unode->grids) { | if (unode->grids) { | ||||
| MEM_freeN(unode->grids); | MEM_freeN(unode->grids); | ||||
| } | } | ||||
| if (unode->orig_co) { | if (unode->orig_co) { | ||||
| MEM_freeN(unode->orig_co); | MEM_freeN(unode->orig_co); | ||||
| ▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | LISTBASE_FOREACH (SculptUndoNode *, unode, &usculpt->nodes) { | ||||
| if (unode->type == type) { | if (unode->type == type) { | ||||
| return unode; | return unode; | ||||
| } | } | ||||
| } | } | ||||
| return sculpt_undo_alloc_node_type(object, type); | return sculpt_undo_alloc_node_type(object, type); | ||||
| } | } | ||||
| static void sculpt_undo_store_faces(SculptSession *ss, SculptUndoNode *unode) | |||||
| { | |||||
| unode->faces_num = 0; | |||||
| PBVHFaceIter fd; | |||||
| BKE_pbvh_face_iter_begin (ss->pbvh, unode->node, fd) { | |||||
| unode->faces_num++; | |||||
| } | |||||
| BKE_pbvh_face_iter_end(fd); | |||||
| unode->faces = MEM_malloc_arrayN(sizeof(*unode->faces), unode->faces_num, __func__); | |||||
| BKE_pbvh_face_iter_begin (ss->pbvh, unode->node, fd) { | |||||
| unode->faces[fd.i] = fd.face; | |||||
| } | |||||
| BKE_pbvh_face_iter_end(fd); | |||||
| } | |||||
| static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, SculptUndoType type) | static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, SculptUndoType type) | ||||
| { | { | ||||
| UndoSculpt *usculpt = sculpt_undo_get_nodes(); | UndoSculpt *usculpt = sculpt_undo_get_nodes(); | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| int totvert = 0; | int totvert = 0; | ||||
| int allvert = 0; | int allvert = 0; | ||||
| int totgrid = 0; | int totgrid = 0; | ||||
| int maxgrid = 0; | int maxgrid = 0; | ||||
| int gridsize = 0; | int gridsize = 0; | ||||
| int *grids = NULL; | int *grids = NULL; | ||||
| SculptUndoNode *unode = sculpt_undo_alloc_node_type(ob, type); | SculptUndoNode *unode = sculpt_undo_alloc_node_type(ob, type); | ||||
| unode->node = node; | unode->node = node; | ||||
| if (node) { | if (node) { | ||||
| BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert); | BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert); | ||||
| BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, &maxgrid, &gridsize, NULL); | BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, &maxgrid, &gridsize, NULL); | ||||
| unode->totvert = totvert; | unode->totvert = totvert; | ||||
| } | } | ||||
| bool need_loops = type == SCULPT_UNDO_COLOR; | bool need_loops = type == SCULPT_UNDO_COLOR; | ||||
| const bool need_faces = type == SCULPT_UNDO_FACE_SETS; | |||||
| if (need_loops) { | if (need_loops) { | ||||
| int totloop; | int totloop; | ||||
| BKE_pbvh_node_num_loops(ss->pbvh, node, &totloop); | BKE_pbvh_node_num_loops(ss->pbvh, node, &totloop); | ||||
| unode->loop_index = MEM_calloc_arrayN(totloop, sizeof(int), __func__); | unode->loop_index = MEM_calloc_arrayN(totloop, sizeof(int), __func__); | ||||
| unode->maxloop = 0; | unode->maxloop = 0; | ||||
| unode->totloop = totloop; | unode->totloop = totloop; | ||||
| size_t alloc_size = sizeof(int) * (size_t)totloop; | size_t alloc_size = sizeof(int) * (size_t)totloop; | ||||
| usculpt->undo_size += alloc_size; | usculpt->undo_size += alloc_size; | ||||
| } | } | ||||
| if (need_faces) { | |||||
| sculpt_undo_store_faces(ss, unode); | |||||
| const size_t alloc_size = sizeof(*unode->faces) * (size_t)unode->faces_num; | |||||
| usculpt->undo_size += alloc_size; | |||||
| } | |||||
| switch (type) { | switch (type) { | ||||
| case SCULPT_UNDO_COORDS: { | case SCULPT_UNDO_COORDS: { | ||||
| size_t alloc_size = sizeof(*unode->co) * (size_t)allvert; | size_t alloc_size = sizeof(*unode->co) * (size_t)allvert; | ||||
| unode->co = MEM_callocN(alloc_size, "SculptUndoNode.co"); | unode->co = MEM_callocN(alloc_size, "SculptUndoNode.co"); | ||||
| usculpt->undo_size += alloc_size; | usculpt->undo_size += alloc_size; | ||||
| /* Needed for original data lookup. */ | /* Needed for original data lookup. */ | ||||
| alloc_size = sizeof(*unode->no) * (size_t)allvert; | alloc_size = sizeof(*unode->no) * (size_t)allvert; | ||||
| Show All 34 Lines | case SCULPT_UNDO_COLOR: { | ||||
| usculpt->undo_size += alloc_size_loop; | usculpt->undo_size += alloc_size_loop; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case SCULPT_UNDO_DYNTOPO_BEGIN: | case SCULPT_UNDO_DYNTOPO_BEGIN: | ||||
| case SCULPT_UNDO_DYNTOPO_END: | case SCULPT_UNDO_DYNTOPO_END: | ||||
| case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: | case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: | ||||
| BLI_assert_msg(0, "Dynamic topology should've already been handled"); | BLI_assert_msg(0, "Dynamic topology should've already been handled"); | ||||
| break; | |||||
| case SCULPT_UNDO_GEOMETRY: | case SCULPT_UNDO_GEOMETRY: | ||||
| case SCULPT_UNDO_FACE_SETS: | break; | ||||
| case SCULPT_UNDO_FACE_SETS: { | |||||
| const size_t alloc_size = sizeof(*unode->face_sets) * (size_t)unode->faces_num; | |||||
| usculpt->undo_size += alloc_size; | |||||
| break; | break; | ||||
| } | } | ||||
| } | |||||
| if (maxgrid) { | if (maxgrid) { | ||||
| /* Multires. */ | /* Multires. */ | ||||
| unode->maxgrid = maxgrid; | unode->maxgrid = maxgrid; | ||||
| unode->totgrid = totgrid; | unode->totgrid = totgrid; | ||||
| unode->gridsize = gridsize; | unode->gridsize = gridsize; | ||||
| const size_t alloc_size = sizeof(*unode->grids) * (size_t)totgrid; | const size_t alloc_size = sizeof(*unode->grids) * (size_t)totgrid; | ||||
| ▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | static SculptUndoNode *sculpt_undo_geometry_push(Object *object, SculptUndoType type) | ||||
| unode->geometry_clear_pbvh = true; | unode->geometry_clear_pbvh = true; | ||||
| SculptUndoNodeGeometry *geometry = sculpt_undo_geometry_get(unode); | SculptUndoNodeGeometry *geometry = sculpt_undo_geometry_get(unode); | ||||
| sculpt_undo_geometry_store_data(geometry, object); | sculpt_undo_geometry_store_data(geometry, object); | ||||
| return unode; | return unode; | ||||
| } | } | ||||
| static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType type) | static void sculpt_undo_store_face_sets(SculptSession *ss, SculptUndoNode *unode) | ||||
| { | { | ||||
| UndoSculpt *usculpt = sculpt_undo_get_nodes(); | unode->face_sets = MEM_malloc_arrayN(sizeof(*unode->face_sets), unode->faces_num, __func__); | ||||
| SculptUndoNode *unode = MEM_callocN(sizeof(*unode), __func__); | |||||
| BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname)); | PBVHFaceIter fd; | ||||
| unode->type = type; | BKE_pbvh_face_iter_begin (ss->pbvh, unode->node, fd) { | ||||
| unode->applied = true; | unode->face_sets[fd.i] = fd.face_set ? *fd.face_set : SCULPT_FACE_SET_NONE; | ||||
| Mesh *me = BKE_object_get_original_mesh(ob); | |||||
| unode->face_sets = MEM_callocN(me->totpoly * sizeof(int), "sculpt face sets"); | |||||
| const int *face_sets = CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, ".sculpt_face_set"); | |||||
| if (face_sets) { | |||||
| for (int i = 0; i < me->totpoly; i++) { | |||||
| unode->face_sets[i] = face_sets[i]; | |||||
| } | |||||
| } | |||||
| else { | |||||
| memset(unode->face_sets, SCULPT_FACE_SET_NONE, sizeof(int) * me->totpoly); | |||||
| } | } | ||||
| BKE_pbvh_face_iter_end(fd); | |||||
| BLI_addtail(&usculpt->nodes, unode); | |||||
| return unode; | |||||
| } | } | ||||
| static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, SculptUndoType type) | static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, SculptUndoType type) | ||||
| { | { | ||||
| UndoSculpt *usculpt = sculpt_undo_get_nodes(); | UndoSculpt *usculpt = sculpt_undo_get_nodes(); | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| PBVHVertexIter vd; | PBVHVertexIter vd; | ||||
| ▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | if (ss->bm || ELEM(type, SCULPT_UNDO_DYNTOPO_BEGIN, SCULPT_UNDO_DYNTOPO_END)) { | ||||
| BLI_thread_unlock(LOCK_CUSTOM1); | BLI_thread_unlock(LOCK_CUSTOM1); | ||||
| return unode; | return unode; | ||||
| } | } | ||||
| if (type == SCULPT_UNDO_GEOMETRY) { | if (type == SCULPT_UNDO_GEOMETRY) { | ||||
| unode = sculpt_undo_geometry_push(ob, type); | unode = sculpt_undo_geometry_push(ob, type); | ||||
| BLI_thread_unlock(LOCK_CUSTOM1); | BLI_thread_unlock(LOCK_CUSTOM1); | ||||
| return unode; | return unode; | ||||
| } | } | ||||
| if (type == SCULPT_UNDO_FACE_SETS) { | |||||
| unode = sculpt_undo_face_sets_push(ob, type); | |||||
| BLI_thread_unlock(LOCK_CUSTOM1); | |||||
| return unode; | |||||
| } | |||||
| if ((unode = SCULPT_undo_get_node(node, type))) { | if ((unode = SCULPT_undo_get_node(node, type))) { | ||||
| BLI_thread_unlock(LOCK_CUSTOM1); | BLI_thread_unlock(LOCK_CUSTOM1); | ||||
| return unode; | return unode; | ||||
| } | } | ||||
| unode = sculpt_undo_alloc_node(ob, node, type); | unode = sculpt_undo_alloc_node(ob, node, type); | ||||
| /* NOTE: If this ever becomes a bottleneck, make a lock inside of the node. | /* NOTE: If this ever becomes a bottleneck, make a lock inside of the node. | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | switch (type) { | ||||
| case SCULPT_UNDO_COLOR: | case SCULPT_UNDO_COLOR: | ||||
| sculpt_undo_store_color(ob, unode); | sculpt_undo_store_color(ob, unode); | ||||
| break; | break; | ||||
| case SCULPT_UNDO_DYNTOPO_BEGIN: | case SCULPT_UNDO_DYNTOPO_BEGIN: | ||||
| case SCULPT_UNDO_DYNTOPO_END: | case SCULPT_UNDO_DYNTOPO_END: | ||||
| case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: | case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: | ||||
| BLI_assert_msg(0, "Dynamic topology should've already been handled"); | BLI_assert_msg(0, "Dynamic topology should've already been handled"); | ||||
| case SCULPT_UNDO_GEOMETRY: | case SCULPT_UNDO_GEOMETRY: | ||||
| break; | |||||
| case SCULPT_UNDO_FACE_SETS: | case SCULPT_UNDO_FACE_SETS: | ||||
| sculpt_undo_store_face_sets(ss, unode); | |||||
| break; | break; | ||||
| } | } | ||||
| /* Store sculpt pivot. */ | /* Store sculpt pivot. */ | ||||
| copy_v3_v3(unode->pivot_pos, ss->pivot_pos); | copy_v3_v3(unode->pivot_pos, ss->pivot_pos); | ||||
| copy_v3_v3(unode->pivot_rot, ss->pivot_rot); | copy_v3_v3(unode->pivot_rot, ss->pivot_rot); | ||||
| /* Store active shape key. */ | /* Store active shape key. */ | ||||
| ▲ Show 20 Lines • Show All 423 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. */ | ||||
Done Inline ActionsUnnecessary change HooglyBoogly: Unnecessary change | |||||
| 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 | |||||
Unnecessary change here