[Bf-blender-cvs] [cb9de95d61b] master: Sculpt: Face Set Edit Operator

Pablo Dobarro noreply at git.blender.org
Tue Jun 9 19:13:23 CEST 2020


Commit: cb9de95d61b32f90788875f20e046095bb6310ad
Author: Pablo Dobarro
Date:   Thu Jun 4 00:23:29 2020 +0200
Branches: master
https://developer.blender.org/rBcb9de95d61b32f90788875f20e046095bb6310ad

Sculpt: Face Set Edit Operator

This operator performs an edit operation in the active face set defined
by the cursor position and updates the visibility. For now, it has a
Grow and Shrink operations, similar to Select More/Less in edit mode or
to the mask filter Grow/Shrink modes. More operations can be added in
the future.

In multires, this updates the visibility of an entire face from the base
mesh at once, which makes it very convenient to edit the visible area
without manipulating the face set directly.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D7367

===================================================================

M	release/scripts/presets/keyconfig/keymap_data/blender_default.py
M	release/scripts/startup/bl_ui/space_view3d.py
M	source/blender/blenkernel/BKE_paint.h
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/editors/sculpt_paint/sculpt_face_set.c
M	source/blender/editors/sculpt_paint/sculpt_intern.h

===================================================================

diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 1d43c486bca..878c3bfb01f 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -4318,6 +4318,10 @@ def km_sculpt(params):
          {"properties": [("mode", 'SHOW_ALL')]}),
         ("sculpt.mask_expand", {"type": 'W', "value": 'PRESS', "shift": True},
          {"properties": [("use_normals", False), ("keep_previous_mask", False), ("invert", False), ("smooth_iterations", 0), ("create_face_set", True)]}),
+        ("sculpt.face_set_edit", {"type": 'W', "value": 'PRESS', "ctrl": True},
+         {"properties": [("mode", "GROW")]}),
+        ("sculpt.face_set_edit", {"type": 'W', "value": 'PRESS', "ctrl": True, "alt": True},
+         {"properties": [("mode", "SHRINK")]}),
         # Subdivision levels
         *_template_items_object_subdivision_set(),
         ("object.subdivision_set", {"type": 'PAGE_UP', "value": 'PRESS'},
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 7f1047cec74..c982d8e93a9 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -3126,6 +3126,14 @@ class VIEW3D_MT_face_sets(Menu):
 
         layout.separator()
 
+        op = layout.operator("sculpt.face_set_edit", text='Grow Face Set')
+        op.mode = 'GROW'
+
+        op = layout.operator("sculpt.face_set_edit", text='Shrink Face Set')
+        op.mode = 'SHRINK'
+
+        layout.separator()
+
         op = layout.operator("sculpt.face_set_change_visibility", text='Invert Visible Face Sets')
         op.mode = 'INVERT'
 
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 1e52349a942..4d30c5c7fce 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -315,6 +315,8 @@ typedef struct SculptSession {
   /* Mesh Face Sets */
   /* Total number of polys of the base mesh. */
   int totfaces;
+  /* Face sets store its visibility in the sign of the integer, using the absolute value as the
+   * Face Set ID. Positive IDs are visible, negative IDs are hidden. */
   int *face_sets;
 
   /* BMesh for dynamic topology sculpting */
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 2c050cba6b7..75c88047914 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -7907,4 +7907,5 @@ void ED_operatortypes_sculpt(void)
   WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
   WM_operatortype_append(SCULPT_OT_face_sets_init);
   WM_operatortype_append(SCULPT_OT_cloth_filter);
+  WM_operatortype_append(SCULPT_OT_face_sets_edit);
 }
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index cbdbab14690..7bb54366204 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -978,3 +978,170 @@ void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot)
 
   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
+
+typedef enum eSculptFaceSetEditMode {
+  SCULPT_FACE_SET_EDIT_GROW = 0,
+  SCULPT_FACE_SET_EDIT_SHRINK = 1,
+} 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",
+    },
+    {0, NULL, 0, NULL, NULL},
+};
+
+static void sculpt_face_set_grow(Object *ob,
+                                 SculptSession *ss,
+                                 int *prev_face_sets,
+                                 const int active_face_set_id)
+{
+  Mesh *mesh = BKE_mesh_from_object(ob);
+  for (int p = 0; p < mesh->totpoly; p++) {
+    const MPoly *c_poly = &mesh->mpoly[p];
+    for (int l = 0; l < c_poly->totloop; l++) {
+      const MLoop *c_loop = &mesh->mloop[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) {
+
+          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,
+                                   int *prev_face_sets,
+                                   const int active_face_set_id)
+{
+  Mesh *mesh = BKE_mesh_from_object(ob);
+  for (int p = 0; p < mesh->totpoly; p++) {
+    if (abs(prev_face_sets[p]) == active_face_set_id) {
+      const MPoly *c_poly = &mesh->mpoly[p];
+      for (int l = 0; l < c_poly->totloop; l++) {
+        const MLoop *c_loop = &mesh->mloop[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) {
+            if (abs(prev_face_sets[neighbor_face_index]) != active_face_set_id) {
+              ss->face_sets[p] = prev_face_sets[neighbor_face_index];
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+static void sculpt_face_set_apply_edit(Object *ob, const int active_face_set_id, const int mode)
+{
+  SculptSession *ss = ob->sculpt;
+
+  int *prev_face_sets = MEM_dupallocN(ss->face_sets);
+
+  switch (mode) {
+    case SCULPT_FACE_SET_EDIT_GROW:
+      sculpt_face_set_grow(ob, ss, prev_face_sets, active_face_set_id);
+      break;
+    case SCULPT_FACE_SET_EDIT_SHRINK:
+      sculpt_face_set_shrink(ob, ss, prev_face_sets, active_face_set_id);
+      break;
+  }
+
+  MEM_SAFE_FREE(prev_face_sets);
+}
+
+static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+  Object *ob = CTX_data_active_object(C);
+  SculptSession *ss = ob->sculpt;
+  ARegion *region = CTX_wm_region(C);
+  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);
+
+  PBVH *pbvh = ob->sculpt->pbvh;
+  PBVHNode **nodes;
+  int totnode;
+  BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+  if (!nodes) {
+    return OPERATOR_CANCELLED;
+  }
+
+  SCULPT_undo_push_begin("face set edit");
+  SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
+
+  const int active_face_set = SCULPT_active_face_set_get(ss);
+
+  sculpt_face_set_apply_edit(ob, abs(active_face_set), mode);
+
+  SCULPT_undo_push_end();
+
+  /* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
+  SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
+
+  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);
+  }
+
+  ED_region_tag_redraw(region);
+  DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+
+  View3D *v3d = CTX_wm_view3d(C);
+  if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
+    DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+  }
+
+  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", "");
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 50808b04276..0e27658e848 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -890,6 +890,7 @@ void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot);
 void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot);
 void SCULPT_OT_face_sets_init(struct wmOperatorType *ot);
 void SCULPT_OT_face_sets_create(struct wmOperatorType *ot);
+void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot);
 
 /* Transform. */
 void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot);



More information about the Bf-blender-cvs mailing list