[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