Multi-Object Editing
This adds initial multi-object editing support. - Selected objects are used when entering edit & pose modes. - Selection & tools work on all objects however many tools need porting See: T54641 for remaining tasks. Indentation will be done separately. See patch: D3101
This commit is contained in:
@@ -93,7 +93,14 @@
|
||||
|
||||
static int edbm_subdivide_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(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(view_layer, &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);
|
||||
const int cuts = RNA_int_get(op->ptr, "number_cuts");
|
||||
float smooth = RNA_float_get(op->ptr, "smoothness");
|
||||
@@ -116,6 +123,9 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
|
||||
RNA_int_get(op->ptr, "seed"));
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(objects);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
@@ -367,16 +377,22 @@ enum {
|
||||
MESH_DELETE_ONLY_FACE = 4,
|
||||
};
|
||||
|
||||
static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int totelem[3])
|
||||
static void edbm_report_delete_info(ReportList *reports, const int totelem_old[3], const int totelem_new[3])
|
||||
{
|
||||
BKE_reportf(reports, RPT_INFO,
|
||||
"Removed: %d vertices, %d edges, %d faces",
|
||||
totelem[0] - bm->totvert, totelem[1] - bm->totedge, totelem[2] - bm->totface);
|
||||
totelem_old[0] - totelem_new[0], totelem_old[1] - totelem_new[1], totelem_old[2] - totelem_new[2]);
|
||||
}
|
||||
|
||||
static int edbm_delete_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(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(view_layer, &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);
|
||||
const int type = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
@@ -412,6 +428,8 @@ static int edbm_delete_exec(bContext *C, wmOperator *op)
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
|
||||
} /* objects */
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -467,18 +485,26 @@ static bool bm_face_is_loose(BMFace *f)
|
||||
|
||||
static int edbm_delete_loose_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
int totelem_old_sel[3];
|
||||
int totelem_old[3];
|
||||
|
||||
uint objects_len = 0;
|
||||
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
|
||||
|
||||
EDBM_mesh_stats_multi(objects, objects_len, totelem_old, totelem_old_sel);
|
||||
|
||||
const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && totelem_old_sel[0]);
|
||||
const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && totelem_old_sel[1]);
|
||||
const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && totelem_old_sel[2]);
|
||||
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects[ob_index];
|
||||
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMesh *bm = em->bm;
|
||||
BMIter iter;
|
||||
|
||||
const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && bm->totvertsel);
|
||||
const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && bm->totedgesel);
|
||||
const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && bm->totfacesel);
|
||||
|
||||
const int totelem[3] = {bm->totvert, bm->totedge, bm->totface};
|
||||
|
||||
|
||||
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
|
||||
|
||||
if (use_faces) {
|
||||
@@ -520,8 +546,14 @@ static int edbm_delete_loose_exec(bContext *C, wmOperator *op)
|
||||
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
}
|
||||
|
||||
edbm_report_delete_info(op->reports, bm, totelem);
|
||||
int totelem_new[3];
|
||||
EDBM_mesh_stats_multi(objects, objects_len, totelem_new, NULL);
|
||||
|
||||
edbm_report_delete_info(op->reports, totelem_old, totelem_new);
|
||||
|
||||
MEM_SAFE_FREE(objects);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
@@ -4096,11 +4128,18 @@ void MESH_OT_poke(wmOperatorType *ot)
|
||||
|
||||
static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMOperator bmop;
|
||||
const int quad_method = RNA_enum_get(op->ptr, "quad_method");
|
||||
const int ngon_method = RNA_enum_get(op->ptr, "ngon_method");
|
||||
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(view_layer, &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);
|
||||
BMOperator bmop;
|
||||
BMOIter oiter;
|
||||
BMFace *f;
|
||||
|
||||
@@ -4117,11 +4156,15 @@ static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
|
||||
|
||||
EDBM_selectmode_flush(em);
|
||||
|
||||
// XXX, TODO
|
||||
#if 0
|
||||
if (!EDBM_op_finish(em, &bmop, op, true)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
@@ -4155,7 +4198,22 @@ void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
|
||||
|
||||
static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(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(view_layer, &objects_len);
|
||||
|
||||
bool is_face_pair;
|
||||
|
||||
{
|
||||
int totelem_sel[3];
|
||||
EDBM_mesh_stats_multi(objects, objects_len, NULL, totelem_sel);
|
||||
is_face_pair = (totelem_sel[2] == 2);
|
||||
}
|
||||
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects[ob_index];
|
||||
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
bool do_seam, do_sharp, do_uvs, do_vcols, do_materials;
|
||||
float angle_face_threshold, angle_shape_threshold;
|
||||
@@ -4164,7 +4222,7 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
|
||||
/* When joining exactly 2 faces, no limit.
|
||||
* this is useful for one off joins while editing. */
|
||||
prop = RNA_struct_find_property(op->ptr, "face_threshold");
|
||||
if ((em->bm->totfacesel == 2) &&
|
||||
if (is_face_pair &&
|
||||
(RNA_property_is_set(op->ptr, prop) == false))
|
||||
{
|
||||
angle_face_threshold = DEG2RADF(180.0f);
|
||||
@@ -4174,7 +4232,7 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
|
||||
prop = RNA_struct_find_property(op->ptr, "shape_threshold");
|
||||
if ((em->bm->totfacesel == 2) &&
|
||||
if (is_face_pair &&
|
||||
(RNA_property_is_set(op->ptr, prop) == false))
|
||||
{
|
||||
angle_shape_threshold = DEG2RADF(180.0f);
|
||||
@@ -4197,10 +4255,11 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
|
||||
BM_ELEM_SELECT, angle_face_threshold, angle_shape_threshold,
|
||||
do_seam, do_sharp, do_uvs, do_vcols, do_materials))
|
||||
{
|
||||
return OPERATOR_CANCELLED;
|
||||
continue;
|
||||
}
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
@@ -4727,11 +4786,28 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
|
||||
|
||||
static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
int totelem_old[3] = {0, 0, 0};
|
||||
int totelem_new[3] = {0, 0, 0};
|
||||
|
||||
uint objects_len = 0;
|
||||
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &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);
|
||||
BMesh *bm = em->bm;
|
||||
totelem_old[0] += bm->totvert;
|
||||
totelem_old[1] += bm->totedge;
|
||||
totelem_old[2] += bm->totface;
|
||||
} /* objects */
|
||||
|
||||
const float thresh = RNA_float_get(op->ptr, "threshold");
|
||||
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects[ob_index];
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMesh *bm = em->bm;
|
||||
const int totelem[3] = {bm->totvert, bm->totedge, bm->totface};
|
||||
|
||||
if (!EDBM_op_callf(
|
||||
em, op,
|
||||
@@ -4746,7 +4822,12 @@ static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
|
||||
edbm_report_delete_info(op->reports, bm, totelem);
|
||||
totelem_new[0] += bm->totvert;
|
||||
totelem_new[1] += bm->totedge;
|
||||
totelem_new[2] += bm->totface;
|
||||
}
|
||||
|
||||
edbm_report_delete_info(op->reports, totelem_old, totelem_new);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user