diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index c66acb0509f..cccb5389037 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -4274,7 +4274,10 @@ class VIEW3D_MT_edit_mesh_faces_data(Menu): layout.separator() + layout.operator("mesh.flip_quad_tessellation") + if with_freestyle: + layout.separator() layout.operator("mesh.mark_freestyle_face").clear = False layout.operator("mesh.mark_freestyle_face", text="Clear Freestyle Face").clear = True diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 0ffb3f6652e..4e0df875740 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -270,6 +270,23 @@ static BMOpDefine bmo_reverse_faces_def = { BMO_OPTYPE_FLAG_NORMALS_CALC), }; +/* + * Flip Quad Tessellation + * + * Flip the tessellation direction of the selected quads. +*/ +static BMOpDefine bmo_flip_quad_tessellation_def = { + "flip_quad_tessellation", + /* slot_in */ + { + {"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, + {{'\0'}} + }, + {{{'\0'}}}, /* no output */ + bmo_flip_quad_tessellation_exec, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC), +}; + /* * Edge Bisect. * @@ -2128,6 +2145,7 @@ const BMOpDefine *bmo_opdefines[] = { &bmo_extrude_face_region_def, &bmo_extrude_vert_indiv_def, &bmo_find_doubles_def, + &bmo_flip_quad_tessellation_def, &bmo_grid_fill_def, &bmo_inset_individual_def, &bmo_inset_region_def, diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h index 0f628c04d98..3562b4da71a 100644 --- a/source/blender/bmesh/intern/bmesh_operators_private.h +++ b/source/blender/bmesh/intern/bmesh_operators_private.h @@ -88,3 +88,4 @@ void bmo_triangulate_exec(BMesh *bm, BMOperator *op); void bmo_unsubdivide_exec(BMesh *bm, BMOperator *op); void bmo_weld_verts_exec(BMesh *bm, BMOperator *op); void bmo_wireframe_exec(BMesh *bm, BMOperator *op); +void bmo_flip_quad_tessellation_exec(BMesh *bm, BMOperator *op); diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index bff1d1d587d..5ca7c3bafaf 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -177,6 +177,7 @@ void BM_face_normal_flip_ex(BMesh *bm, int cd_loop_mdisp_offset, bool use_loop_mdisp_flip) ATTR_NONNULL(); void BM_face_normal_flip(BMesh *bm, BMFace *f) ATTR_NONNULL(); + /** * BM POINT IN FACE * diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index a821fa2b744..8d4ba5c11f8 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -147,6 +147,22 @@ void bmo_reverse_faces_exec(BMesh *bm, BMOperator *op) #define SEL_FLAG 1 #define SEL_ORIG 2 +void bmo_flip_quad_tessellation_exec(BMesh *bm, BMOperator *op) +{ + BMOIter siter; + BMFace *f; + bool changed = false; + BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { + if (f->len == 4) { + f->l_first = f->l_first->next; + changed = true; + } + } + if (changed) { + bm->elem_index_dirty |= BM_LOOP; + } +} + static void bmo_face_flag_set_flush(BMesh *bm, BMFace *f, const short oflag, const bool value) { BMLoop *l_iter; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 620d6c2ea5e..f5c4bf6facc 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -2227,6 +2227,18 @@ static void edbm_flip_normals_custom_loop_normals(Object *obedit, BMEditMesh *em }); } +static void edbm_flip_quad_tessellation(wmOperator *op, Object *obedit, BMEditMesh *em) +{ + if (EDBM_op_callf(em, op, "flip_quad_tessellation faces=%hf", BM_ELEM_SELECT)) { + EDBM_update(obedit->data, + &(const struct EDBMUpdate_Params){ + .calc_looptri = true, + .calc_normals = false, + .is_destructive = false, + }); + } +} + static void edbm_flip_normals_face_winding(wmOperator *op, Object *obedit, BMEditMesh *em) { @@ -2253,6 +2265,27 @@ static void edbm_flip_normals_face_winding(wmOperator *op, Object *obedit, BMEdi } } +static int edbm_flip_quad_tessellation_exec(bContext *C, wmOperator *op) +{ + const Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + scene, view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totfacesel == 0) { + continue; + } + edbm_flip_quad_tessellation(op, obedit, em); + } + + MEM_freeN(objects); + return OPERATOR_FINISHED; +} + static int edbm_flip_normals_exec(bContext *C, wmOperator *op) { const bool only_clnors = RNA_boolean_get(op->ptr, "only_clnors"); @@ -9934,4 +9967,18 @@ void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot) "Strength to use for assigning or selecting face influence for weighted normal modifier"); } +void MESH_OT_flip_quad_tessellation(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Flip Quad Tessellation"; + ot->description = "Flips the tessellation of selected quads"; + ot->idname = "MESH_OT_flip_quad_tessellation"; + + ot->exec = edbm_flip_quad_tessellation_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /** \} */ diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 0e20bb18595..7386fe69b6c 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -294,6 +294,7 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot); void MESH_OT_average_normals(struct wmOperatorType *ot); void MESH_OT_smooth_normals(struct wmOperatorType *ot); void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot); +void MESH_OT_flip_quad_tessellation(struct wmOperatorType *ot); /* *** editmesh_mask_extract.c *** */ diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index c3c3abd46a1..b9afeae275b 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -193,6 +193,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_average_normals); WM_operatortype_append(MESH_OT_smooth_normals); WM_operatortype_append(MESH_OT_mod_weighted_strength); + WM_operatortype_append(MESH_OT_flip_quad_tessellation); } #if 0 /* UNUSED, remove? */