diff --git a/source/blender/bmesh/operators/bmo_symmetrize.c b/source/blender/bmesh/operators/bmo_symmetrize.c index 248c7268ac6..172f0d40b27 100644 --- a/source/blender/bmesh/operators/bmo_symmetrize.c +++ b/source/blender/bmesh/operators/bmo_symmetrize.c @@ -361,6 +361,12 @@ static BMFace *symm_face_create_v(BMesh *bm, BMFace *example, BMFace *f_new; int i; + /* TODO: calling symmetrize in dynamic-topology sculpt mode + * frequently tries to create faces of length less than two, + * should investigate further */ + if (len < 3) + return NULL; + for (i = 0; i < len; i++) { int j = (i + 1) % len; fe[i] = BM_edge_exists(fv[i], fv[j]); @@ -374,6 +380,7 @@ static BMFace *symm_face_create_v(BMesh *bm, BMFace *example, BM_elem_attrs_copy(bm, bm, example, f_new); BM_face_select_set(bm, f_new, TRUE); BMO_elem_flag_enable(bm, f_new, SYMM_OUTPUT_GEOM); + return f_new; } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 12475c61bca..81f18b6a551 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -5734,18 +5734,6 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op) void MESH_OT_symmetrize(struct wmOperatorType *ot) { - static EnumPropertyItem axis_direction_items[] = { - {BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""}, - {BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""}, - - {BMO_SYMMETRIZE_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y to +Y", ""}, - {BMO_SYMMETRIZE_POSITIVE_Y, "POSITIVE_Y", 0, "+Y to -Y", ""}, - - {BMO_SYMMETRIZE_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z to +Z", ""}, - {BMO_SYMMETRIZE_POSITIVE_Z, "POSITIVE_Z", 0, "+Z to -Z", ""}, - {0, NULL, 0, NULL, NULL}, - }; - /* identifiers */ ot->name = "Symmetrize"; ot->description = "Enforce symmetry (both form and topological) across an axis"; @@ -5758,7 +5746,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "direction", axis_direction_items, - BMO_SYMMETRIZE_NEGATIVE_X, - "Direction", "Which sides to copy from and to"); + ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items, + BMO_SYMMETRIZE_NEGATIVE_X, + "Direction", "Which sides to copy from and to"); } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index af304d04d5d..95f997d46b1 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4712,6 +4712,50 @@ static void SCULPT_OT_optimize(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/********************* Dynamic topology symmetrize ********************/ + +static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + const Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + + /* To simplify undo for symmetrize, all BMesh elements are logged + * as deleted, then after symmetrize operation all BMesh elements + * are logged as added (as opposed to attempting to store just the + * parts that symmetrize modifies) */ + sculpt_undo_push_begin("Dynamic topology symmetrize"); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); + BM_log_before_all_removed(ss->bm, ss->bm_log); + + /* Symmetrize and re-triangulate */ + BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS, + "symmetrize input=%avef direction=%i", + sd->symmetrize_direction); + sculpt_dynamic_topology_triangulate(ss->bm); + + /* Finish undo */ + BM_log_all_added(ss->bm, ss->bm_log); + sculpt_undo_push_end(); + + /* Redraw */ + sculpt_pbvh_clear(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_symmetrize(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Symmetrize"; + ot->idname = "SCULPT_OT_symmetrize"; + + /* api callbacks */ + ot->exec = sculpt_symmetrize_exec; + ot->poll = sculpt_and_dynamic_topology_poll; +} + /**** Toggle operator for turning sculpt mode on or off ****/ static void sculpt_init_session(Scene *scene, Object *ob) @@ -4887,4 +4931,5 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_set_persistent_base); WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle); WM_operatortype_append(SCULPT_OT_optimize); + WM_operatortype_append(SCULPT_OT_symmetrize); } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 0d1ef7af591..6dcc74d74e7 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -832,6 +832,11 @@ typedef struct Sculpt { /* Maximum edge length for dynamic topology sculpting (in pixels) */ int detail_size; + + /* Direction used for SCULPT_OT_symmetrize operator */ + int symmetrize_direction; + + int pad; } Sculpt; typedef struct UvSculpt { diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 49f881ce285..6733d8a5c05 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -90,6 +90,8 @@ extern EnumPropertyItem brush_sculpt_tool_items[]; extern EnumPropertyItem brush_vertex_tool_items[]; extern EnumPropertyItem brush_image_tool_items[]; +extern EnumPropertyItem symmetrize_direction_items[]; + extern EnumPropertyItem texture_type_items[]; extern EnumPropertyItem lamp_type_items[]; diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index e3b41222a38..fb4295ddb53 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -40,6 +40,9 @@ #include "WM_api.h" #include "WM_types.h" +#include "BLI_utildefines.h" +#include "bmesh.h" + static EnumPropertyItem particle_edit_hair_brush_items[] = { {PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush"}, {PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs"}, @@ -52,6 +55,18 @@ static EnumPropertyItem particle_edit_hair_brush_items[] = { {0, NULL, 0, NULL, NULL} }; +EnumPropertyItem symmetrize_direction_items[] = { + {BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""}, + {BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""}, + + {BMO_SYMMETRIZE_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y to +Y", ""}, + {BMO_SYMMETRIZE_POSITIVE_Y, "POSITIVE_Y", 0, "+Y to -Y", ""}, + + {BMO_SYMMETRIZE_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z to +Z", ""}, + {BMO_SYMMETRIZE_POSITIVE_Z, "POSITIVE_Z", 0, "+Z to -Z", ""}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME #include "MEM_guardedalloc.h" @@ -341,6 +356,10 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Collapse Short Edges", "In dynamic-topology mode, collapse short edges " "in addition to subdividing long ones"); + + prop = RNA_def_property(srna, "symmetrize_direction", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, symmetrize_direction_items); + RNA_def_property_ui_text(prop, "Direction", "Source and destination for symmetrize operator"); }