diff options
author | Hans Goudey <h.goudey@me.com> | 2022-09-16 07:06:04 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-09-16 07:06:04 +0300 |
commit | ac76da2944a2b2810fc17f793ba313144beddd78 (patch) | |
tree | fca6b90fe56d76a4df4d86fcdb5924f22855c953 /source/blender | |
parent | 15d85c54c3f960814068074bcdff0a5546fa4d5a (diff) |
Revert "UI: Use full word for face set operator name, tweak description"
This reverts commit 15d85c54c3f960814068074bcdff0a5546fa4d5a.
Included a separate change/new file by mistake. Sorry for the noise.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_face_set.cc | 1505 |
1 files changed, 0 insertions, 1505 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc deleted file mode 100644 index 1d59ba34d3e..00000000000 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc +++ /dev/null @@ -1,1505 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2020 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup edsculpt - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" -#include "BLI_hash.h" -#include "BLI_math.h" -#include "BLI_task.h" - -#include "DNA_brush_types.h" -#include "DNA_customdata_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BKE_brush.h" -#include "BKE_ccg.h" -#include "BKE_colortools.h" -#include "BKE_context.h" -#include "BKE_customdata.h" -#include "BKE_mesh.h" -#include "BKE_mesh_fair.h" -#include "BKE_mesh_mapping.h" -#include "BKE_multires.h" -#include "BKE_node.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_pbvh.h" -#include "BKE_scene.h" - -#include "DEG_depsgraph.h" - -#include "WM_api.h" -#include "WM_message.h" -#include "WM_toolsystem.h" -#include "WM_types.h" - -#include "ED_object.h" -#include "ED_screen.h" -#include "ED_sculpt.h" -#include "ED_view3d.h" -#include "paint_intern.h" -#include "sculpt_intern.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "bmesh.h" - -#include <math.h> -#include <stdlib.h> - -/* Utils. */ - -int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh) -{ - const int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); - if (!face_sets) { - return SCULPT_FACE_SET_NONE; - } - - int next_face_set_id = 0; - for (int i = 0; i < mesh->totpoly; i++) { - next_face_set_id = max_ii(next_face_set_id, face_sets[i]); - } - next_face_set_id++; - - return next_face_set_id; -} - -void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, const int new_id) -{ - int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); - if (!face_sets) { - return; - } - - for (int i = 0; i < mesh->totpoly; i++) { - if (face_sets[i] == SCULPT_FACE_SET_NONE) { - face_sets[i] = new_id; - } - } -} - -int ED_sculpt_face_sets_active_update_and_get(bContext *C, Object *ob, const float mval[2]) -{ - SculptSession *ss = ob->sculpt; - if (!ss) { - return SCULPT_FACE_SET_NONE; - } - - SculptCursorGeometryInfo gi; - if (!SCULPT_cursor_geometry_info_update(C, &gi, mval, false)) { - return SCULPT_FACE_SET_NONE; - } - - return SCULPT_active_face_set_get(ss); -} - -/* Draw Face Sets Brush. */ - -static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float bstrength = ss->cache->bstrength; - - PBVHVertexIter vd; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { - MeshElemMap *vert_map = &ss->pmap[vd.index]; - for (int j = 0; j < ss->pmap[vd.index].count; j++) { - const MPoly *p = &ss->mpoly[vert_map->indices[j]]; - - float poly_center[3]; - BKE_mesh_calc_poly_center(p, &ss->mloop[p->loopstart], mvert, poly_center); - - if (!sculpt_brush_test_sq_fn(&test, poly_center)) { - continue; - } - const bool face_hidden = ss->hide_poly && ss->hide_poly[vert_map->indices[j]]; - if (face_hidden) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.vertex, - thread_id); - - if (fade > 0.05f) { - ss->face_sets[vert_map->indices[j]] = ss->cache->paint_face_set; - } - } - } - else if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.vertex, - thread_id); - - if (fade > 0.05f) { - SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set); - } - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - float bstrength = ss->cache->bstrength; - - PBVHVertexIter vd; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - - const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0); - /* This operations needs a strength tweak as the relax deformation is too weak by default. */ - if (relax_face_sets) { - bstrength *= 2.0f; - } - - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) { - continue; - } - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.vertex, - thread_id); - - SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co); - if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); - } - } - BKE_pbvh_vertex_iter_end; -} - -void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - BKE_curvemapping_init(brush->curve); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - if (ss->cache->alt_smooth) { - SCULPT_boundary_info_ensure(ob); - for (int i = 0; i < 4; i++) { - BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings); - } - } - else { - BLI_task_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings); - } -} - -/* Face Sets Operators */ - -typedef enum eSculptFaceGroupsCreateModes { - SCULPT_FACE_SET_MASKED = 0, - SCULPT_FACE_SET_VISIBLE = 1, - SCULPT_FACE_SET_ALL = 2, - SCULPT_FACE_SET_SELECTION = 3, -} eSculptFaceGroupsCreateModes; - -static EnumPropertyItem prop_sculpt_face_set_create_types[] = { - { - SCULPT_FACE_SET_MASKED, - "MASKED", - 0, - "Face Set from Masked", - "Create a new Face Set from the masked faces", - }, - { - SCULPT_FACE_SET_VISIBLE, - "VISIBLE", - 0, - "Face Set from Visible", - "Create a new Face Set from the visible vertices", - }, - { - SCULPT_FACE_SET_ALL, - "ALL", - 0, - "Face Set Full Mesh", - "Create an unique Face Set with all faces in the sculpt", - }, - { - SCULPT_FACE_SET_SELECTION, - "SELECTION", - 0, - "Face Set from Edit Mode Selection", - "Create an Face Set corresponding to the Edit Mode face selection", - }, - {0, nullptr, 0, nullptr, nullptr}, -}; - -static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) -{ - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - - const int mode = RNA_enum_get(op->ptr, "mode"); - - /* Dyntopo not supported. */ - if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { - return OPERATOR_CANCELLED; - } - - Mesh *mesh = ob->data; - ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); - - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED, false); - - const int tot_vert = SCULPT_vertex_count_get(ss); - float threshold = 0.5f; - - PBVH *pbvh = ob->sculpt->pbvh; - PBVHNode **nodes; - int totnode; - BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode); - - if (!nodes) { - return OPERATOR_CANCELLED; - } - - SCULPT_undo_push_begin(ob, op); - SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS); - - const int next_face_set = SCULPT_face_set_next_available_get(ss); - - if (mode == SCULPT_FACE_SET_MASKED) { - for (int i = 0; i < tot_vert; i++) { - PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); - - if (SCULPT_vertex_mask_get(ss, vertex) >= threshold && - SCULPT_vertex_visible_get(ss, vertex)) { - SCULPT_vertex_face_set_set(ss, vertex, next_face_set); - } - } - } - - if (mode == SCULPT_FACE_SET_VISIBLE) { - - /* If all vertices in the sculpt are visible, create the new face set and update the default - * color. This way the new face set will be white, which is a quick way of disabling all face - * sets and the performance hit of rendering the overlay. */ - bool all_visible = true; - for (int i = 0; i < tot_vert; i++) { - PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); - - if (!SCULPT_vertex_visible_get(ss, vertex)) { - all_visible = false; - break; - } - } - - if (all_visible) { - mesh->face_sets_color_default = next_face_set; - BKE_pbvh_face_sets_color_set( - ss->pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default); - } - - for (int i = 0; i < tot_vert; i++) { - PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); - - if (SCULPT_vertex_visible_get(ss, vertex)) { - SCULPT_vertex_face_set_set(ss, vertex, next_face_set); - } - } - } - - if (mode == SCULPT_FACE_SET_ALL) { - for (int i = 0; i < tot_vert; i++) { - PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); - - SCULPT_vertex_face_set_set(ss, vertex, next_face_set); - } - } - - if (mode == SCULPT_FACE_SET_SELECTION) { - BMesh *bm; - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); - bm = BM_mesh_create(&allocsize, - &((struct BMeshCreateParams){ - .use_toolflags = true, - })); - - BM_mesh_bm_from_me(bm, - mesh, - (&(struct BMeshFromMeshParams){ - .calc_face_normal = true, - .calc_vert_normal = true, - })); - - BMIter iter; - BMFace *f; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - ss->face_sets[BM_elem_index_get(f)] = next_face_set; - } - } - BM_mesh_free(bm); - } - - for (int i = 0; i < totnode; i++) { - BKE_pbvh_node_mark_redraw(nodes[i]); - } - - MEM_SAFE_FREE(nodes); - - SCULPT_undo_push_end(ob); - - SCULPT_tag_update_overlays(C); - - return OPERATOR_FINISHED; -} - -void SCULPT_OT_face_sets_create(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Create Face Set"; - ot->idname = "SCULPT_OT_face_sets_create"; - ot->description = "Create a new Face Set"; - - /* api callbacks */ - ot->exec = sculpt_face_set_create_exec; - ot->poll = SCULPT_mode_poll; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum( - ot->srna, "mode", prop_sculpt_face_set_create_types, SCULPT_FACE_SET_MASKED, "Mode", ""); -} - -typedef enum eSculptFaceSetsInitMode { - SCULPT_FACE_SETS_FROM_LOOSE_PARTS = 0, - SCULPT_FACE_SETS_FROM_MATERIALS = 1, - SCULPT_FACE_SETS_FROM_NORMALS = 2, - SCULPT_FACE_SETS_FROM_UV_SEAMS = 3, - SCULPT_FACE_SETS_FROM_CREASES = 4, - SCULPT_FACE_SETS_FROM_SHARP_EDGES = 5, - SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT = 6, - SCULPT_FACE_SETS_FROM_FACE_MAPS = 7, - SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES = 8, -} eSculptFaceSetsInitMode; - -static EnumPropertyItem prop_sculpt_face_sets_init_types[] = { - { - SCULPT_FACE_SETS_FROM_LOOSE_PARTS, - "LOOSE_PARTS", - 0, - "Face Sets from Loose Parts", - "Create a Face Set per loose part in the mesh", - }, - { - SCULPT_FACE_SETS_FROM_MATERIALS, - "MATERIALS", - 0, - "Face Sets from Material Slots", - "Create a Face Set per Material Slot", - }, - { - SCULPT_FACE_SETS_FROM_NORMALS, - "NORMALS", - 0, - "Face Sets from Mesh Normals", - "Create Face Sets for Faces that have similar normal", - }, - { - SCULPT_FACE_SETS_FROM_UV_SEAMS, - "UV_SEAMS", - 0, - "Face Sets from UV Seams", - "Create Face Sets using UV Seams as boundaries", - }, - { - SCULPT_FACE_SETS_FROM_CREASES, - "CREASES", - 0, - "Face Sets from Edge Creases", - "Create Face Sets using Edge Creases as boundaries", - }, - { - SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT, - "BEVEL_WEIGHT", - 0, - "Face Sets from Bevel Weight", - "Create Face Sets using Bevel Weights as boundaries", - }, - { - SCULPT_FACE_SETS_FROM_SHARP_EDGES, - "SHARP_EDGES", - 0, - "Face Sets from Sharp Edges", - "Create Face Sets using Sharp Edges as boundaries", - }, - { - SCULPT_FACE_SETS_FROM_FACE_MAPS, - "FACE_MAPS", - 0, - "Face Sets from Face Maps", - "Create a Face Set per Face Map", - }, - { - SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES, - "FACE_SET_BOUNDARIES", - 0, - "Face Sets from Face Set Boundaries", - "Create a Face Set per isolated Face Set", - }, - - {0, nullptr, 0, nullptr, nullptr}, -}; - -typedef bool (*face_sets_flood_fill_test)( - BMesh *bm, BMFace *from_f, BMEdge *from_e, BMFace *to_f, const float threshold); - -static bool sculpt_face_sets_init_loose_parts_test(BMesh *UNUSED(bm), - BMFace *from_f, - BMEdge *UNUSED(from_e), - BMFace *to_f, - const float UNUSED(threshold)) -{ - return BM_elem_flag_test(from_f, BM_ELEM_HIDDEN) == BM_elem_flag_test(to_f, BM_ELEM_HIDDEN); -} - -static bool sculpt_face_sets_init_normals_test( - BMesh *UNUSED(bm), BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float threshold) -{ - return fabsf(dot_v3v3(from_f->no, to_f->no)) > threshold; -} - -static bool sculpt_face_sets_init_uv_seams_test(BMesh *UNUSED(bm), - BMFace *UNUSED(from_f), - BMEdge *from_e, - BMFace *UNUSED(to_f), - const float UNUSED(threshold)) -{ - return !BM_elem_flag_test(from_e, BM_ELEM_SEAM); -} - -static bool sculpt_face_sets_init_crease_test( - BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold) -{ - return BM_elem_float_data_get(&bm->edata, from_e, CD_CREASE) < threshold; -} - -static bool sculpt_face_sets_init_bevel_weight_test( - BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold) -{ - return BM_elem_float_data_get(&bm->edata, from_e, CD_BWEIGHT) < threshold; -} - -static bool sculpt_face_sets_init_sharp_edges_test(BMesh *UNUSED(bm), - BMFace *UNUSED(from_f), - BMEdge *from_e, - BMFace *UNUSED(to_f), - const float UNUSED(threshold)) -{ - return BM_elem_flag_test(from_e, BM_ELEM_SMOOTH); -} - -static bool sculpt_face_sets_init_face_set_boundary_test( - BMesh *bm, BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float UNUSED(threshold)) -{ - const int cd_face_sets_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS); - return BM_ELEM_CD_GET_INT(from_f, cd_face_sets_offset) == - BM_ELEM_CD_GET_INT(to_f, cd_face_sets_offset); -} - -static void sculpt_face_sets_init_flood_fill(Object *ob, - face_sets_flood_fill_test test, - const float threshold) -{ - SculptSession *ss = ob->sculpt; - Mesh *mesh = ob->data; - BMesh *bm; - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); - bm = BM_mesh_create(&allocsize, - &((struct BMeshCreateParams){ - .use_toolflags = true, - })); - - BM_mesh_bm_from_me(bm, - mesh, - (&(struct BMeshFromMeshParams){ - .calc_face_normal = true, - .calc_vert_normal = true, - })); - - BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces"); - const int totfaces = mesh->totpoly; - - int *face_sets = ss->face_sets; - - BM_mesh_elem_table_init(bm, BM_FACE); - BM_mesh_elem_table_ensure(bm, BM_FACE); - - int next_face_set = 1; - - for (int i = 0; i < totfaces; i++) { - if (BLI_BITMAP_TEST(visited_faces, i)) { - continue; - } - GSQueue *queue; - queue = BLI_gsqueue_new(sizeof(int)); - - face_sets[i] = next_face_set; - BLI_BITMAP_ENABLE(visited_faces, i); - BLI_gsqueue_push(queue, &i); - - while (!BLI_gsqueue_is_empty(queue)) { - int from_f; - BLI_gsqueue_pop(queue, &from_f); - - BMFace *f, *f_neighbor; - BMEdge *ed; - BMIter iter_a, iter_b; - - f = BM_face_at_index(bm, from_f); - - BM_ITER_ELEM (ed, &iter_a, f, BM_EDGES_OF_FACE) { - BM_ITER_ELEM (f_neighbor, &iter_b, ed, BM_FACES_OF_EDGE) { - if (f_neighbor == f) { - continue; - } - int neighbor_face_index = BM_elem_index_get(f_neighbor); - if (BLI_BITMAP_TEST(visited_faces, neighbor_face_index)) { - continue; - } - if (!test(bm, f, ed, f_neighbor, threshold)) { - continue; - } - - face_sets[neighbor_face_index] = next_face_set; - BLI_BITMAP_ENABLE(visited_faces, neighbor_face_index); - BLI_gsqueue_push(queue, &neighbor_face_index); - } - } - } - - next_face_set += 1; - - BLI_gsqueue_free(queue); - } - - MEM_SAFE_FREE(visited_faces); - - BM_mesh_free(bm); -} - -static void sculpt_face_sets_init_loop(Object *ob, const int mode) -{ - Mesh *mesh = ob->data; - SculptSession *ss = ob->sculpt; - BMesh *bm; - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); - bm = BM_mesh_create(&allocsize, - &((struct BMeshCreateParams){ - .use_toolflags = true, - })); - - BM_mesh_bm_from_me(bm, - mesh, - (&(struct BMeshFromMeshParams){ - .calc_face_normal = true, - .calc_vert_normal = true, - })); - BMIter iter; - BMFace *f; - - const int cd_fmaps_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP); - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (mode == SCULPT_FACE_SETS_FROM_MATERIALS) { - ss->face_sets[BM_elem_index_get(f)] = (int)(f->mat_nr + 1); - } - else if (mode == SCULPT_FACE_SETS_FROM_FACE_MAPS) { - if (cd_fmaps_offset != -1) { - ss->face_sets[BM_elem_index_get(f)] = BM_ELEM_CD_GET_INT(f, cd_fmaps_offset) + 2; - } - else { - ss->face_sets[BM_elem_index_get(f)] = 1; - } - } - } - BM_mesh_free(bm); -} - -static int sculpt_face_set_init_exec(bContext *C, wmOperator *op) -{ - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - - const int mode = RNA_enum_get(op->ptr, "mode"); - - /* Dyntopo not supported. */ - if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { - return OPERATOR_CANCELLED; - } - - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); - - PBVH *pbvh = ob->sculpt->pbvh; - PBVHNode **nodes; - int totnode; - BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode); - - if (!nodes) { - return OPERATOR_CANCELLED; - } - - SCULPT_undo_push_begin(ob, op); - SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS); - - const float threshold = RNA_float_get(op->ptr, "threshold"); - - Mesh *mesh = ob->data; - ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); - - switch (mode) { - case SCULPT_FACE_SETS_FROM_LOOSE_PARTS: - sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_loose_parts_test, threshold); - break; - case SCULPT_FACE_SETS_FROM_MATERIALS: - sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_MATERIALS); - break; - case SCULPT_FACE_SETS_FROM_NORMALS: - sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_normals_test, threshold); - break; - case SCULPT_FACE_SETS_FROM_UV_SEAMS: - sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_uv_seams_test, threshold); - break; - case SCULPT_FACE_SETS_FROM_CREASES: - sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_crease_test, threshold); - break; - case SCULPT_FACE_SETS_FROM_SHARP_EDGES: - sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_sharp_edges_test, threshold); - break; - case SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT: - sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_bevel_weight_test, threshold); - break; - case SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES: - sculpt_face_sets_init_flood_fill( - ob, sculpt_face_sets_init_face_set_boundary_test, threshold); - break; - case SCULPT_FACE_SETS_FROM_FACE_MAPS: - sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_FACE_MAPS); - break; - } - - SCULPT_undo_push_end(ob); - - /* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */ - SCULPT_visibility_sync_all_from_faces(ob); - - for (int i = 0; i < totnode; i++) { - BKE_pbvh_node_mark_update_visibility(nodes[i]); - } - - BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility); - - MEM_SAFE_FREE(nodes); - - if (BKE_pbvh_type(pbvh) == PBVH_FACES) { - BKE_mesh_flush_hidden_from_verts(ob->data); - } - - SCULPT_tag_update_overlays(C); - - return OPERATOR_FINISHED; -} - -void SCULPT_OT_face_sets_init(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Initialize Face Sets"; - ot->idname = "SCULPT_OT_face_sets_init"; - ot->description = "Set the value for all faces sets on the mesh"; - - /* api callbacks */ - ot->exec = sculpt_face_set_init_exec; - ot->poll = SCULPT_mode_poll; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum( - ot->srna, "mode", prop_sculpt_face_sets_init_types, SCULPT_FACE_SET_MASKED, "Mode", ""); - RNA_def_float( - ot->srna, - "threshold", - 0.5f, - 0.0f, - 1.0f, - "Threshold", - "Minimum value to consider a certain attribute a boundary when creating the Face Sets", - 0.0f, - 1.0f); -} - -typedef enum eSculptFaceGroupVisibilityModes { - SCULPT_FACE_SET_VISIBILITY_TOGGLE = 0, - SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE = 1, - SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE = 2, - SCULPT_FACE_SET_VISIBILITY_INVERT = 3, - SCULPT_FACE_SET_VISIBILITY_SHOW_ALL = 4, -} eSculptFaceGroupVisibilityModes; - -static EnumPropertyItem prop_sculpt_face_sets_change_visibility_types[] = { - { - SCULPT_FACE_SET_VISIBILITY_TOGGLE, - "TOGGLE", - 0, - "Toggle Visibility", - "Hide all Face Sets except for the active one", - }, - { - SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE, - "SHOW_ACTIVE", - 0, - "Show Active Face Set", - "Show Active Face Set", - }, - { - SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE, - "HIDE_ACTIVE", - 0, - "Hide Active Face Sets", - "Hide Active Face Sets", - }, - { - SCULPT_FACE_SET_VISIBILITY_INVERT, - "INVERT", - 0, - "Invert Face Set Visibility", - "Invert Face Set Visibility", - }, - { - SCULPT_FACE_SET_VISIBILITY_SHOW_ALL, - "SHOW_ALL", - 0, - "Show All Face Sets", - "Show All Face Sets", - }, - {0, nullptr, 0, nullptr, nullptr}, -}; - -static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) -{ - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - - /* Dyntopo not supported. */ - if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { - return OPERATOR_CANCELLED; - } - - if (!ss->face_sets) { - return OPERATOR_CANCELLED; - } - - Mesh *mesh = BKE_object_get_original_mesh(ob); - - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - - const int tot_vert = SCULPT_vertex_count_get(ss); - const int mode = RNA_enum_get(op->ptr, "mode"); - const int active_face_set = SCULPT_active_face_set_get(ss); - - SCULPT_undo_push_begin(ob, op); - - PBVH *pbvh = ob->sculpt->pbvh; - PBVHNode **nodes; - int totnode; - - BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode); - - if (totnode == 0) { - MEM_SAFE_FREE(nodes); - return OPERATOR_CANCELLED; - } - - SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS); - - if (mode == SCULPT_FACE_SET_VISIBILITY_TOGGLE) { - bool hidden_vertex = false; - - /* This can fail with regular meshes with non-manifold geometry as the visibility state can't - * be synced from face sets to non-manifold vertices. */ - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - for (int i = 0; i < tot_vert; i++) { - PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); - - if (!SCULPT_vertex_visible_get(ss, vertex)) { - hidden_vertex = true; - break; - } - } - } - - if (ss->hide_poly) { - for (int i = 0; i < ss->totfaces; i++) { - if (ss->hide_poly[i]) { - hidden_vertex = true; - break; - } - } - } - - ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); - - if (hidden_vertex) { - SCULPT_face_visibility_all_set(ss, true); - } - else { - SCULPT_face_visibility_all_set(ss, false); - SCULPT_face_set_visibility_set(ss, active_face_set, true); - } - } - - if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ALL) { - /* As an optimization, free the hide attribute when making all geometry visible. This allows - * reduced memory usage without manually clearing it later, and allows sculpt operations to - * avoid checking element's hide status. */ - CustomData_free_layer_named(&mesh->pdata, ".hide_poly", mesh->totpoly); - ss->hide_poly = nullptr; - BKE_pbvh_update_hide_attributes_from_mesh(pbvh); - } - - if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE) { - ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); - SCULPT_face_visibility_all_set(ss, false); - SCULPT_face_set_visibility_set(ss, active_face_set, true); - } - - if (mode == SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE) { - ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); - SCULPT_face_set_visibility_set(ss, active_face_set, false); - } - - if (mode == SCULPT_FACE_SET_VISIBILITY_INVERT) { - ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); - SCULPT_face_visibility_all_invert(ss); - } - - /* For modes that use the cursor active vertex, update the rotation origin for viewport - * navigation. */ - if (ELEM(mode, SCULPT_FACE_SET_VISIBILITY_TOGGLE, SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE)) { - UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; - float location[3]; - copy_v3_v3(location, SCULPT_active_vertex_co_get(ss)); - mul_m4_v3(ob->obmat, location); - copy_v3_v3(ups->average_stroke_accum, location); - ups->average_stroke_counter = 1; - ups->last_stroke_valid = true; - } - - /* Sync face sets visibility and vertex visibility. */ - SCULPT_visibility_sync_all_from_faces(ob); - - SCULPT_undo_push_end(ob); - - for (int i = 0; i < totnode; i++) { - BKE_pbvh_node_mark_update_visibility(nodes[i]); - } - - BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility); - - MEM_SAFE_FREE(nodes); - - SCULPT_tag_update_overlays(C); - - return OPERATOR_FINISHED; -} - -static int sculpt_face_sets_change_visibility_invoke(bContext *C, - wmOperator *op, - const wmEvent *event) -{ - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - - /* Update the active vertex and Face Set using the cursor position to avoid relying on the paint - * cursor updates. */ - SculptCursorGeometryInfo sgi; - const float mval_fl[2] = {UNPACK2(event->mval)}; - SCULPT_vertex_random_access_ensure(ss); - SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); - - return sculpt_face_sets_change_visibility_exec(C, op); -} - -void SCULPT_OT_face_sets_change_visibility(wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Face Sets Visibility"; - ot->idname = "SCULPT_OT_face_set_change_visibility"; - ot->description = "Change the visibility of the Face Sets of the sculpt"; - - /* Api callbacks. */ - ot->exec = sculpt_face_sets_change_visibility_exec; - ot->invoke = sculpt_face_sets_change_visibility_invoke; - ot->poll = SCULPT_mode_poll; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum(ot->srna, - "mode", - prop_sculpt_face_sets_change_visibility_types, - SCULPT_FACE_SET_VISIBILITY_TOGGLE, - "Mode", - ""); -} - -static int sculpt_face_sets_randomize_colors_exec(bContext *C, wmOperator *UNUSED(op)) -{ - - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - - /* Dyntopo not supported. */ - if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { - return OPERATOR_CANCELLED; - } - - if (!ss->face_sets) { - return OPERATOR_CANCELLED; - } - - PBVH *pbvh = ob->sculpt->pbvh; - PBVHNode **nodes; - int totnode; - Mesh *mesh = ob->data; - - mesh->face_sets_color_seed += 1; - if (ss->face_sets) { - const int random_index = clamp_i(ss->totfaces * BLI_hash_int_01(mesh->face_sets_color_seed), - 0, - max_ii(0, ss->totfaces - 1)); - mesh->face_sets_color_default = ss->face_sets[random_index]; - } - BKE_pbvh_face_sets_color_set(pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default); - - BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode); - for (int i = 0; i < totnode; i++) { - BKE_pbvh_node_mark_redraw(nodes[i]); - } - - MEM_SAFE_FREE(nodes); - - SCULPT_tag_update_overlays(C); - - return OPERATOR_FINISHED; -} - -void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Randomize Face Sets Colors"; - ot->idname = "SCULPT_OT_face_sets_randomize_colors"; - ot->description = "Generates a new set of random colors to render the Face Sets in the viewport"; - - /* Api callbacks. */ - ot->exec = sculpt_face_sets_randomize_colors_exec; - ot->poll = SCULPT_mode_poll; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -typedef enum eSculptFaceSetEditMode { - SCULPT_FACE_SET_EDIT_GROW = 0, - SCULPT_FACE_SET_EDIT_SHRINK = 1, - SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY = 2, - SCULPT_FACE_SET_EDIT_FAIR_POSITIONS = 3, - SCULPT_FACE_SET_EDIT_FAIR_TANGENCY = 4, -} eSculptFaceSetEditMode; - -static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = { - { - SCULPT_FACE_SET_EDIT_GROW, - "GROW", - 0, - "Grow Face Set", - "Grows the Face Sets boundary by one face based on mesh topology", - }, - { - SCULPT_FACE_SET_EDIT_SHRINK, - "SHRINK", - 0, - "Shrink Face Set", - "Shrinks the Face Sets boundary by one face based on mesh topology", - }, - { - SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY, - "DELETE_GEOMETRY", - 0, - "Delete Geometry", - "Deletes the faces that are assigned to the Face Set", - }, - { - SCULPT_FACE_SET_EDIT_FAIR_POSITIONS, - "FAIR_POSITIONS", - 0, - "Fair Positions", - "Creates a smooth as possible geometry patch from the Face Set minimizing changes in " - "vertex positions", - }, - { - SCULPT_FACE_SET_EDIT_FAIR_TANGENCY, - "FAIR_TANGENCY", - 0, - "Fair Tangency", - "Creates a smooth as possible geometry patch from the Face Set minimizing changes in " - "vertex tangents", - }, - {0, nullptr, 0, nullptr, nullptr}, -}; - -static void sculpt_face_set_grow(Object *ob, - SculptSession *ss, - const int *prev_face_sets, - const int active_face_set_id, - const bool modify_hidden) -{ - Mesh *mesh = BKE_mesh_from_object(ob); - const MPoly *polys = BKE_mesh_polys(mesh); - const MLoop *loops = BKE_mesh_loops(mesh); - - for (int p = 0; p < mesh->totpoly; p++) { - if (!modify_hidden && prev_face_sets[p] <= 0) { - continue; - } - const MPoly *c_poly = &polys[p]; - for (int l = 0; l < c_poly->totloop; l++) { - const MLoop *c_loop = &loops[c_poly->loopstart + l]; - const MeshElemMap *vert_map = &ss->pmap[c_loop->v]; - for (int i = 0; i < vert_map->count; i++) { - const int neighbor_face_index = vert_map->indices[i]; - if (neighbor_face_index == p) { - continue; - } - if (abs(prev_face_sets[neighbor_face_index]) == active_face_set_id) { - ss->face_sets[p] = active_face_set_id; - } - } - } - } -} - -static void sculpt_face_set_shrink(Object *ob, - SculptSession *ss, - const int *prev_face_sets, - const int active_face_set_id, - const bool modify_hidden) -{ - Mesh *mesh = BKE_mesh_from_object(ob); - const MPoly *polys = BKE_mesh_polys(mesh); - const MLoop *loops = BKE_mesh_loops(mesh); - for (int p = 0; p < mesh->totpoly; p++) { - if (!modify_hidden && prev_face_sets[p] <= 0) { - continue; - } - if (abs(prev_face_sets[p]) == active_face_set_id) { - const MPoly *c_poly = &polys[p]; - for (int l = 0; l < c_poly->totloop; l++) { - const MLoop *c_loop = &loops[c_poly->loopstart + l]; - const MeshElemMap *vert_map = &ss->pmap[c_loop->v]; - for (int i = 0; i < vert_map->count; i++) { - const int neighbor_face_index = vert_map->indices[i]; - if (neighbor_face_index == p) { - continue; - } - if (abs(prev_face_sets[neighbor_face_index]) != active_face_set_id) { - ss->face_sets[p] = prev_face_sets[neighbor_face_index]; - } - } - } - } - } -} - -static bool check_single_face_set(SculptSession *ss, int *face_sets, const bool check_visible_only) -{ - if (face_sets == nullptr) { - return true; - } - int first_face_set = SCULPT_FACE_SET_NONE; - if (check_visible_only) { - for (int f = 0; f < ss->totfaces; f++) { - if (ss->hide_poly && ss->hide_poly[f]) { - continue; - } - first_face_set = face_sets[f]; - break; - } - } - else { - first_face_set = face_sets[0]; - } - - if (first_face_set == SCULPT_FACE_SET_NONE) { - return true; - } - - for (int f = 0; f < ss->totfaces; f++) { - if (check_visible_only && ss->hide_poly && ss->hide_poly[f]) { - continue; - } - if (face_sets[f] != first_face_set) { - return false; - } - } - return true; -} - -static void sculpt_face_set_delete_geometry(Object *ob, - SculptSession *ss, - const int active_face_set_id, - const bool modify_hidden) -{ - - Mesh *mesh = ob->data; - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); - BMesh *bm = BM_mesh_create(&allocsize, - &((struct BMeshCreateParams){ - .use_toolflags = true, - })); - - BM_mesh_bm_from_me(bm, - mesh, - (&(struct BMeshFromMeshParams){ - .calc_face_normal = true, - .calc_vert_normal = true, - })); - - BM_mesh_elem_table_init(bm, BM_FACE); - BM_mesh_elem_table_ensure(bm, BM_FACE); - BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - BMIter iter; - BMFace *f; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - const int face_index = BM_elem_index_get(f); - if (!modify_hidden && ss->hide_poly && ss->hide_poly[face_index]) { - continue; - } - BM_elem_flag_set(f, BM_ELEM_TAG, ss->face_sets[face_index] == active_face_set_id); - } - BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES); - BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - - BM_mesh_bm_to_me(nullptr, - bm, - ob->data, - (&(struct BMeshToMeshParams){ - .calc_object_remap = false, - })); - - BM_mesh_free(bm); -} - -static void sculpt_face_set_edit_fair_face_set(Object *ob, - const int active_face_set_id, - const int fair_order) -{ - SculptSession *ss = ob->sculpt; - const int totvert = SCULPT_vertex_count_get(ss); - - Mesh *mesh = ob->data; - bool *fair_verts = MEM_malloc_arrayN(totvert, sizeof(bool), "fair vertices"); - - SCULPT_boundary_info_ensure(ob); - - for (int i = 0; i < totvert; i++) { - PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); - - fair_verts[i] = !SCULPT_vertex_is_boundary(ss, vertex) && - SCULPT_vertex_has_face_set(ss, vertex, active_face_set_id) && - SCULPT_vertex_has_unique_face_set(ss, vertex); - } - - MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss); - BKE_mesh_prefair_and_fair_verts(mesh, mvert, fair_verts, fair_order); - MEM_freeN(fair_verts); -} - -static void sculpt_face_set_apply_edit(Object *ob, - const int active_face_set_id, - const int mode, - const bool modify_hidden) -{ - SculptSession *ss = ob->sculpt; - - switch (mode) { - case SCULPT_FACE_SET_EDIT_GROW: { - int *prev_face_sets = MEM_dupallocN(ss->face_sets); - sculpt_face_set_grow(ob, ss, prev_face_sets, active_face_set_id, modify_hidden); - MEM_SAFE_FREE(prev_face_sets); - break; - } - case SCULPT_FACE_SET_EDIT_SHRINK: { - int *prev_face_sets = MEM_dupallocN(ss->face_sets); - sculpt_face_set_shrink(ob, ss, prev_face_sets, active_face_set_id, modify_hidden); - MEM_SAFE_FREE(prev_face_sets); - break; - } - case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY: - sculpt_face_set_delete_geometry(ob, ss, active_face_set_id, modify_hidden); - break; - case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS: - sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_POSITION); - break; - case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY: - sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_TANGENCY); - break; - } -} - -static bool sculpt_face_set_edit_is_operation_valid(SculptSession *ss, - const eSculptFaceSetEditMode mode, - const bool modify_hidden) -{ - if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { - /* Dyntopo is not supported. */ - return false; - } - - if (mode == SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY) { - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - /* Modification of base mesh geometry requires special remapping of multires displacement, - * which does not happen here. - * Disable delete operation. It can be supported in the future by doing similar displacement - * data remapping as what happens in the mesh edit mode. */ - return false; - } - if (check_single_face_set(ss, ss->face_sets, !modify_hidden)) { - /* Cancel the operator if the mesh only contains one Face Set to avoid deleting the - * entire object. */ - return false; - } - } - - if (ELEM(mode, SCULPT_FACE_SET_EDIT_FAIR_POSITIONS, SCULPT_FACE_SET_EDIT_FAIR_TANGENCY)) { - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - /* TODO: Multires topology representation using grids and duplicates can't be used directly - * by the fair algorithm. Multires topology needs to be exposed in a different way or - * converted to a mesh for this operation. */ - return false; - } - } - - return true; -} - -static void sculpt_face_set_edit_modify_geometry(bContext *C, - Object *ob, - const int active_face_set, - const eSculptFaceSetEditMode mode, - const bool modify_hidden, - wmOperator *op) -{ - ED_sculpt_undo_geometry_begin(ob, op); - sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden); - ED_sculpt_undo_geometry_end(ob); - BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); -} - -static void face_set_edit_do_post_visibility_updates(Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - PBVH *pbvh = ss->pbvh; - - /* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */ - SCULPT_visibility_sync_all_from_faces(ob); - - for (int i = 0; i < totnode; i++) { - BKE_pbvh_node_mark_update_visibility(nodes[i]); - } - - BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility); - - if (BKE_pbvh_type(pbvh) == PBVH_FACES) { - BKE_mesh_flush_hidden_from_verts(ob->data); - } -} - -static void sculpt_face_set_edit_modify_face_sets(Object *ob, - const int active_face_set, - const eSculptFaceSetEditMode mode, - const bool modify_hidden, - wmOperator *op) -{ - PBVH *pbvh = ob->sculpt->pbvh; - PBVHNode **nodes; - int totnode; - BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode); - - if (!nodes) { - return; - } - SCULPT_undo_push_begin(ob, op); - SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS); - sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden); - SCULPT_undo_push_end(ob); - face_set_edit_do_post_visibility_updates(ob, nodes, totnode); - MEM_freeN(nodes); -} - -static void sculpt_face_set_edit_modify_coordinates(bContext *C, - Object *ob, - const int active_face_set, - const eSculptFaceSetEditMode mode, - wmOperator *op) -{ - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - SculptSession *ss = ob->sculpt; - PBVH *pbvh = ss->pbvh; - PBVHNode **nodes; - int totnode; - BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode); - SCULPT_undo_push_begin(ob, op); - for (int i = 0; i < totnode; i++) { - BKE_pbvh_node_mark_update(nodes[i]); - SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COORDS); - } - sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, false); - - if (ss->deform_modifiers_active || ss->shapekey_active) { - SCULPT_flush_stroke_deform(sd, ob, true); - } - SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS); - SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); - SCULPT_undo_push_end(ob); - MEM_freeN(nodes); -} - -static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - - const int mode = RNA_enum_get(op->ptr, "mode"); - const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden"); - - if (!sculpt_face_set_edit_is_operation_valid(ss, mode, modify_hidden)) { - return OPERATOR_CANCELLED; - } - - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); - - /* Update the current active Face Set and Vertex as the operator can be used directly from the - * tool without brush cursor. */ - SculptCursorGeometryInfo sgi; - const float mval_fl[2] = {UNPACK2(event->mval)}; - if (!SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) { - /* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */ - return OPERATOR_CANCELLED; - } - const int active_face_set = SCULPT_active_face_set_get(ss); - - switch (mode) { - case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY: - sculpt_face_set_edit_modify_geometry(C, ob, active_face_set, mode, modify_hidden, op); - break; - case SCULPT_FACE_SET_EDIT_GROW: - case SCULPT_FACE_SET_EDIT_SHRINK: - sculpt_face_set_edit_modify_face_sets(ob, active_face_set, mode, modify_hidden, op); - break; - case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS: - case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY: - sculpt_face_set_edit_modify_coordinates(C, ob, active_face_set, mode, op); - break; - } - - SCULPT_tag_update_overlays(C); - - return OPERATOR_FINISHED; -} - -void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Edit Face Set"; - ot->idname = "SCULPT_OT_face_set_edit"; - ot->description = "Edits the current active Face Set"; - - /* Api callbacks. */ - ot->invoke = sculpt_face_set_edit_invoke; - ot->poll = SCULPT_mode_poll; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum( - ot->srna, "mode", prop_sculpt_face_sets_edit_types, SCULPT_FACE_SET_EDIT_GROW, "Mode", ""); - ot->prop = RNA_def_boolean(ot->srna, - "modify_hidden", - true, - "Modify Hidden", - "Apply the edit operation to hidden Face Sets"); -} |