[Bf-blender-cvs] [985c6464e23] sculpt-dev: Sculpt: Edit face set extrude operation

Pablo Dobarro noreply at git.blender.org
Sat Dec 26 20:11:42 CET 2020


Commit: 985c6464e230b150cb20a9735409c5748f28b8bb
Author: Pablo Dobarro
Date:   Sat Dec 26 20:11:19 2020 +0100
Branches: sculpt-dev
https://developer.blender.org/rB985c6464e230b150cb20a9735409c5748f28b8bb

Sculpt: Edit face set extrude operation

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

M	source/blender/editors/sculpt_paint/sculpt_face_set.c

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

diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index 5e885d97073..7c676e40daa 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -1029,6 +1029,7 @@ typedef enum eSculptFaceSetEditMode {
   SCULPT_FACE_SET_EDIT_FAIR_TANGENCY = 4,
   SCULPT_FACE_SET_EDIT_FAIR_CURVATURE = 5,
   SCULPT_FACE_SET_EDIT_FILL_COMPONENT = 6,
+  SCULPT_FACE_SET_EDIT_EXTRUDE = 7,
 } eSculptFaceSetEditMode;
 
 static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = {
@@ -1086,6 +1087,13 @@ static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = {
         "Fill Component",
         "Expand a Face Set to fill all affected connected components",
     },
+    {
+        SCULPT_FACE_SET_EDIT_EXTRUDE,
+        "EXTRUDE",
+        0,
+        "Extrude",
+        "Extrude a Face Set along the normals of the faces",
+    },
     {0, NULL, 0, NULL, NULL},
 };
 
@@ -1322,7 +1330,7 @@ static bool sculpt_face_set_edit_is_operation_valid(SculptSession *ss,
     return false;
   }
 
-  if (mode == SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY) {
+  if (ELEM(mode, SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY, SCULPT_FACE_SET_EDIT_EXTRUDE)) {
     if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
       /* Modification of base mesh geometry requires special remapping of multires displacement,
        * which does not happen here.
@@ -1430,6 +1438,197 @@ static void sculpt_face_set_edit_modify_coordinates(bContext *C,
   MEM_freeN(nodes);
 }
 
+typedef struct FaceSetExtrudeCD {
+  int active_face_set;
+  float cursor_location[3];
+  float (*orig_co)[3];
+  float init_mval[2];
+  float (*orig_no)[3];
+} FaceSetExtrudeCD;
+
+static void sculpt_face_set_extrude_id(Object *ob, SculptSession *ss, const int active_face_set_id)
+{
+
+  Mesh *mesh = ob->data;
+  const int next_face_set_id = ED_sculpt_face_sets_find_next_available_id(mesh);
+  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,
+                     }));
+
+  BM_mesh_elem_table_init(bm, BM_FACE);
+  BM_mesh_elem_table_ensure(bm, BM_FACE);
+  BM_mesh_elem_hflag_disable_all(bm, BM_ALL_NOLOOP, BM_ELEM_TAG, false);
+  BM_mesh_elem_hflag_disable_all(bm, BM_ALL_NOLOOP, BM_ELEM_SELECT, false);
+  BMIter iter;
+  BMFace *f;
+  BM_mesh_select_mode_set(bm, SCE_SELECT_FACE);
+  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+    const int face_index = BM_elem_index_get(f);
+    const int face_set_id = ss->face_sets[face_index];
+    BM_elem_select_set(bm, f, face_set_id == active_face_set_id);
+    BM_elem_flag_set(f, BM_ELEM_TAG, face_set_id == active_face_set_id);
+  }
+  BM_mesh_select_flush(bm);
+  BM_mesh_select_mode_flush(bm);
+
+  BMOperator extop;
+  BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region");
+  BMO_slot_bool_set(extop.slots_in, "use_normal_flip", true);
+  BMO_slot_bool_set(extop.slots_in, "use_dissolve_ortho_edges", true);
+  BMO_slot_bool_set(extop.slots_in, "use_select_history", true);
+  char htype = BM_ALL_NOLOOP;
+  htype &= ~(BM_VERT | BM_EDGE);
+  if (htype & BM_FACE) {
+    htype |= BM_EDGE;
+  }
+
+  BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", htype, BM_ELEM_SELECT);
+  BMO_op_exec(bm, &extop);
+  BM_mesh_elem_hflag_disable_all(bm, BM_ALL_NOLOOP, BM_ELEM_SELECT, false);
+
+  BMOIter siter;
+  BMElem *ele;
+  BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) {
+    BM_elem_flag_set(ele, BM_ELEM_TAG, true);
+  }
+  BMO_op_finish(bm, &extop);
+
+  /* Set the new Face Set ID for the extrusion. */
+  const int cd_face_sets_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
+  BM_mesh_elem_table_ensure(bm, BM_FACE);
+  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+    const int face_set_id = BM_ELEM_CD_GET_INT(f, cd_face_sets_offset);
+    if (face_set_id == active_face_set_id) {
+      continue;
+    }
+    BMVert *v;
+    BMIter face_iter;
+    BM_ITER_ELEM (v, &face_iter, f, BM_VERTS_OF_FACE) {
+      if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+        BM_ELEM_CD_SET_INT(f, cd_face_sets_offset, next_face_set_id);
+        break;
+      }
+    }
+  }
+
+  BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false);
+  BMO_op_callf(bm,
+               (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+               "recalc_face_normals faces=%hf",
+               BM_ELEM_TAG);
+
+  BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+  BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+  BM_mesh_bm_to_me(NULL,
+                   bm,
+                   ob->data,
+                   (&(struct BMeshToMeshParams){
+                       .calc_object_remap = false,
+                   }));
+
+  BM_mesh_free(bm);
+}
+
+static int sculpt_face_set_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+  Object *ob = CTX_data_active_object(C);
+  SculptSession *ss = ob->sculpt;
+  const int mode = RNA_enum_get(op->ptr, "mode");
+  Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+  BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
+
+  const int totvert = SCULPT_vertex_count_get(ss);
+
+  if (mode != SCULPT_FACE_SET_EDIT_EXTRUDE) {
+    return OPERATOR_FINISHED;
+  }
+
+  if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+    FaceSetExtrudeCD *fsecd = op->customdata;
+    MEM_SAFE_FREE(fsecd->orig_co);
+    MEM_SAFE_FREE(fsecd->orig_no);
+    MEM_SAFE_FREE(op->customdata);
+    ED_sculpt_undo_geometry_end(ob);
+    SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+    return OPERATOR_FINISHED;
+  }
+
+  FaceSetExtrudeCD *fsecd = op->customdata;
+  float depth_world_space[3];
+  float new_pos[3];
+  mul_v3_m4v3(depth_world_space, ob->obmat, fsecd->cursor_location);
+  ViewContext vc;
+  ED_view3d_viewcontext_init(C, &vc, depsgraph);
+  float fmval[2] = {event->mval[0], fsecd->init_mval[1]};
+  ED_view3d_win_to_3d(vc.v3d, vc.region, depth_world_space, fmval, new_pos);
+  float extrude_disp = len_v3v3(depth_world_space, new_pos);
+
+  if (event->mval[0] <= fsecd->init_mval[0]) {
+    extrude_disp *= -1.0f;
+  }
+
+  if (!fsecd->orig_co) {
+    fsecd->orig_co = MEM_calloc_arrayN(totvert, sizeof(float) * 3, "origco");
+    fsecd->orig_no = MEM_calloc_arrayN(totvert, sizeof(float) * 3, "origno");
+    for (int i = 0; i < totvert; i++) {
+      copy_v3_v3(fsecd->orig_co[i], SCULPT_vertex_co_get(ss, i));
+      SCULPT_vertex_normal_get(ss, i, fsecd->orig_no[i]);
+    }
+  }
+
+  MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
+  for (int i = 0; i < totvert; i++) {
+    if (!SCULPT_vertex_has_face_set(ss, i, fsecd->active_face_set)) {
+      continue;
+    }
+    madd_v3_v3v3fl(mvert[i].co, fsecd->orig_co[i], fsecd->orig_no[i], extrude_disp);
+    mvert[i].flag |= ME_VERT_PBVH_UPDATE;
+  }
+
+  PBVHNode **nodes;
+  int totnode;
+  BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+  for (int i = 0; i < totnode; i++) {
+    BKE_pbvh_node_mark_update(nodes[i]);
+  }
+  MEM_SAFE_FREE(nodes);
+
+  SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
+  return OPERATOR_RUNNING_MODAL;
+}
+
+static void sculpt_face_set_extrude_begin(bContext *C,
+                                          wmOperator *op,
+                                          const wmEvent *event,
+                                          Object *ob,
+                                          const int active_face_set,
+                                          const float cursor_location[3])
+{
+  FaceSetExtrudeCD *fsecd = MEM_callocN(sizeof(FaceSetExtrudeCD), "face set extrude cd");
+  fsecd->active_face_set = active_face_set;
+  copy_v3_v3(fsecd->cursor_location, cursor_location);
+  float fmval[2] = {event->mval[0], event->mval[1]};
+  copy_v2_v2(fsecd->init_mval, fmval);
+  op->customdata = fsecd;
+
+  ED_sculpt_undo_geometry_begin(ob, "face set extrude");
+
+  sculpt_face_set_extrude_id(ob, ob->sculpt, active_face_set);
+
+  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 int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
   Object *ob = CTX_data_active_object(C);
@@ -1456,6 +1655,11 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven
   const int active_face_set = SCULPT_active_face_set_get(ss);
 
   switch (mode) {
+    case SCULPT_FACE_SET_EDIT_EXTRUDE:
+      sculpt_face_set_extrude_begin(C, op, event, ob, active_face_set, sgi.location);
+      SCULPT_tag_update_overlays(C);
+      WM_event_add_modal_handler(C, op);
+      return OPERATOR_RUNNING_MODAL;
     case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY:
       sculpt_face_set_edit_modify_geometry(C, ob, active_face_set, mode, modify_hidden);
       break;
@@ -1485,6 +1689,7 @@ void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot)
 
   /* Api callbacks. */
   ot->invoke = sculpt_face_set_edit_invoke;
+  ot->modal = sculpt_face_set_edit_modal;
   ot->poll = SCULPT_mode_poll;
 
   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;



More information about the Bf-blender-cvs mailing list