Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py4
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py8
-rw-r--r--source/blender/blenkernel/BKE_paint.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c167
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h1
6 files changed, 183 insertions, 0 deletions
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);