Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDalai Felinto <dalai@blender.org>2022-03-30 12:07:29 +0300
committerDalai Felinto <dalai@blender.org>2022-03-30 12:07:57 +0300
commit8621fdb10dc402eeff5aa996eeb992a513afd4c0 (patch)
tree9f159edc1f57c61524bcc327a30d24b18a342c73 /source/blender
parent35f34a3cf840852b70c1be5910be5517265d96cc (diff)
Apply Object Transform: Multi-user data support
The current behaviour is to prevent multi-user data from having its transformation applied. However in some particular cases it is possible to apply them: * If all the users of the multi-user data are part of the selection. * If not all the users are in the selection but the selection is made single-user. The active object is used as reference to set the transformation of the other selected objects. Note: For simplicity sake, this new behaviour is only available if all the selection is using the same data. Differential Revision: https://developer.blender.org/D14377
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/editors/object/object_transform.cc189
1 files changed, 176 insertions, 13 deletions
diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc
index da75703a0d9..e279ebbb02e 100644
--- a/source/blender/editors/object/object_transform.cc
+++ b/source/blender/editors/object/object_transform.cc
@@ -587,18 +587,99 @@ static Array<Object *> sorted_selected_editable_objects(bContext *C)
return sorted_objects;
}
+/**
+ * Check if we need and can handle the special multiuser case.
+ */
+static bool apply_objects_internal_can_multiuser(bContext *C)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ if (ELEM(NULL, obact, obact->data)) {
+ return false;
+ }
+
+ if (ID_REAL_USERS(obact->data) == 1) {
+ return false;
+ }
+
+ bool all_objects_same_data = true;
+ bool obact_selected = false;
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
+ if (ob->data != obact->data) {
+ all_objects_same_data = false;
+ break;
+ }
+
+ if (ob == obact) {
+ obact_selected = true;
+ }
+ }
+ CTX_DATA_END;
+
+ return all_objects_same_data && obact_selected;
+}
+
+/**
+ * Check if the current selection need to be made into single user
+ *
+ * It assumes that all selected objects share the same object data.
+ */
+static bool apply_objects_internal_need_single_user(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ BLI_assert(apply_objects_internal_can_multiuser(C));
+
+ /* Counting the number of objects is valid since it's known the
+ * selection is only made up of users of the active objects data. */
+ return (ID_REAL_USERS(ob->data) > CTX_DATA_COUNT(C, selected_editable_objects));
+}
+
static int apply_objects_internal(bContext *C,
ReportList *reports,
bool apply_loc,
bool apply_rot,
bool apply_scale,
- bool do_props)
+ bool do_props,
+ bool do_single_user)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
bool changed = true;
+ bool do_multi_user = apply_objects_internal_can_multiuser(C);
+ float obact_invmat[4][4], obact_parent[4][4], obact_parentinv[4][4];
+
+ /* Only used when do_multi_user is set .*/
+ Object *obact = NULL;
+ bool make_single_user = false;
+
+ if (do_multi_user) {
+ obact = CTX_data_active_object(C);
+ invert_m4_m4(obact_invmat, obact->obmat);
+
+ Object workob;
+ BKE_object_workob_calc_parent(depsgraph, scene, obact, &workob);
+ copy_m4_m4(obact_parent, workob.obmat);
+ copy_m4_m4(obact_parentinv, obact->parentinv);
+
+ if (apply_objects_internal_need_single_user(C)) {
+ if (do_single_user) {
+ make_single_user = true;
+ }
+ else {
+ ID *obact_data = static_cast<ID *>(obact->data);
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting",
+ obact->id.name + 2,
+ BKE_idtype_idcode_to_name(GS(obact_data->name)),
+ obact_data->name + 2);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
/* first check if we can execute */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
@@ -612,7 +693,7 @@ static int apply_objects_internal(bContext *C,
OB_FONT,
OB_GPENCIL)) {
ID *obdata = static_cast<ID *>(ob->data);
- if (ID_REAL_USERS(obdata) > 1) {
+ if (!do_multi_user && ID_REAL_USERS(obdata) > 1) {
BKE_reportf(reports,
RPT_ERROR,
R"(Cannot apply to a multi user: Object "%s", %s "%s", aborting)",
@@ -728,6 +809,15 @@ static int apply_objects_internal(bContext *C,
changed = false;
/* now execute */
+
+ if (make_single_user) {
+ /* Make single user. */
+ ED_object_single_obdata_user(bmain, scene, obact);
+ BKE_main_id_newptr_and_tag_clear(bmain);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ DEG_relations_tag_update(bmain);
+ }
+
Array<Object *> objects = sorted_selected_editable_objects(C);
if (objects.is_empty()) {
return OPERATOR_CANCELLED;
@@ -774,7 +864,14 @@ static int apply_objects_internal(bContext *C,
}
/* apply to object data */
- if (ob->type == OB_MESH) {
+ if (do_multi_user && ob != obact) {
+ /* Don't apply, just set the new object data, the correct
+ * transformations will happen later. */
+ id_us_min((ID *)ob->data);
+ ob->data = obact->data;
+ id_us_plus((ID *)ob->data);
+ }
+ else if (ob->type == OB_MESH) {
Mesh *me = static_cast<Mesh *>(ob->data);
if (apply_scale) {
@@ -882,16 +979,53 @@ static int apply_objects_internal(bContext *C,
continue;
}
- if (apply_loc) {
- zero_v3(ob->loc);
- }
- if (apply_scale) {
- ob->scale[0] = ob->scale[1] = ob->scale[2] = 1.0f;
+ if (do_multi_user && ob != obact) {
+ float _obmat[4][4], _iobmat[4][4];
+ float _mat[4][4];
+
+ copy_m4_m4(_obmat, ob->obmat);
+ invert_m4_m4(_iobmat, _obmat);
+
+ copy_m4_m4(_mat, _obmat);
+ mul_m4_m4_post(_mat, obact_invmat);
+ mul_m4_m4_post(_mat, obact_parent);
+ mul_m4_m4_post(_mat, obact_parentinv);
+
+ if (apply_loc && apply_scale && apply_rot) {
+ BKE_object_apply_mat4(ob, _mat, false, true);
+ }
+ else {
+ Object ob_temp = blender::dna::shallow_copy(*ob);
+ BKE_object_apply_mat4(&ob_temp, _mat, false, true);
+
+ if (apply_loc) {
+ copy_v3_v3(ob->loc, ob_temp.loc);
+ }
+
+ if (apply_scale) {
+ copy_v3_v3(ob->scale, ob_temp.scale);
+ }
+
+ if (apply_rot) {
+ copy_v4_v4(ob->quat, ob_temp.quat);
+ copy_v3_v3(ob->rot, ob_temp.rot);
+ copy_v3_v3(ob->rotAxis, ob_temp.rotAxis);
+ ob->rotAngle = ob_temp.rotAngle;
+ }
+ }
}
- if (apply_rot) {
- zero_v3(ob->rot);
- unit_qt(ob->quat);
- unit_axis_angle(ob->rotAxis, &ob->rotAngle);
+ else {
+ if (apply_loc) {
+ zero_v3(ob->loc);
+ }
+ if (apply_scale) {
+ ob->scale[0] = ob->scale[1] = ob->scale[2] = 1.0f;
+ }
+ if (apply_rot) {
+ zero_v3(ob->rot);
+ unit_qt(ob->quat);
+ unit_axis_angle(ob->rotAxis, &ob->rotAngle);
+ }
}
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
@@ -969,14 +1103,35 @@ static int object_transform_apply_exec(bContext *C, wmOperator *op)
const bool rot = RNA_boolean_get(op->ptr, "rotation");
const bool sca = RNA_boolean_get(op->ptr, "scale");
const bool do_props = RNA_boolean_get(op->ptr, "properties");
+ const bool do_single_user = RNA_boolean_get(op->ptr, "isolate_users");
if (loc || rot || sca) {
- return apply_objects_internal(C, op->reports, loc, rot, sca, do_props);
+ return apply_objects_internal(C, op->reports, loc, rot, sca, do_props, do_single_user);
}
/* allow for redo */
return OPERATOR_FINISHED;
}
+static int object_transform_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *ob = ED_object_active_context(C);
+
+ bool can_handle_multiuser = apply_objects_internal_can_multiuser(C);
+ bool need_single_user = can_handle_multiuser && apply_objects_internal_need_single_user(C);
+
+ if ((ob->data != NULL) && need_single_user) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "isolate_users");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_set(op->ptr, prop, true);
+ }
+ if (RNA_property_boolean_get(op->ptr, prop)) {
+ return WM_operator_confirm_message(
+ C, op, "Create new object-data users and apply transformation");
+ }
+ }
+ return object_transform_apply_exec(C, op);
+}
+
void OBJECT_OT_transform_apply(wmOperatorType *ot)
{
/* identifiers */
@@ -986,6 +1141,7 @@ void OBJECT_OT_transform_apply(wmOperatorType *ot)
/* api callbacks */
ot->exec = object_transform_apply_exec;
+ ot->invoke = object_transform_apply_invoke;
ot->poll = ED_operator_objectmode;
/* flags */
@@ -999,6 +1155,13 @@ void OBJECT_OT_transform_apply(wmOperatorType *ot)
true,
"Apply Properties",
"Modify properties such as curve vertex radius, font size and bone envelope");
+ PropertyRNA *prop = RNA_def_boolean(ot->srna,
+ "isolate_users",
+ false,
+ "Isolate Multi User Data",
+ "Create new object-data users if needed");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */