diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_constraint.py | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 65 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_math_matrix.h | 6 | ||||
-rw-r--r-- | source/blender/blenlib/intern/math_matrix.c | 16 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_280.c | 23 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_convert.c | 3 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_constraint_types.h | 19 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_constraint.c | 54 |
8 files changed, 169 insertions, 19 deletions
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index 0ba9fd0630c..ac1ebedeba4 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -392,7 +392,7 @@ class ConstraintButtonsPanel: sub.active = con.use_z sub.prop(con, "invert_z", text="Invert") - layout.prop(con, "use_offset") + layout.prop(con, "mix_mode", text="Mix") self.space_template(layout, con) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index ccacb85651c..803aae76422 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1802,12 +1802,10 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar bConstraintTarget *ct = targets->first; if (VALID_CONS_TARGET(ct)) { - float loc[3]; - float eul[3], obeul[3]; - float size[3]; + float loc[3], size[3], oldrot[3][3], newrot[3][3]; + float eul[3], obeul[3], defeul[3]; - copy_v3_v3(loc, cob->matrix[3]); - mat4_to_size(size, cob->matrix); + mat4_to_loc_rot_size(loc, oldrot, size, cob->matrix); /* Select the Euler rotation order, defaulting to the owner. */ short rot_order = cob->rotOrder; @@ -1822,11 +1820,28 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar * some of them can be modified below (see bug T21875). */ mat4_to_compatible_eulO(eul, obeul, rot_order, ct->matrix); + /* Prepare the copied euler rotation. */ + bool legacy_offset = false; + + switch (data->mix_mode) { + case ROTLIKE_MIX_OFFSET: + legacy_offset = true; + copy_v3_v3(defeul, obeul); + break; + + case ROTLIKE_MIX_REPLACE: + copy_v3_v3(defeul, obeul); + break; + + default: + zero_v3(defeul); + } + if ((data->flag & ROTLIKE_X) == 0) { - eul[0] = obeul[0]; + eul[0] = defeul[0]; } else { - if (data->flag & ROTLIKE_OFFSET) { + if (legacy_offset) { rotate_eulO(eul, rot_order, 'X', obeul[0]); } @@ -1836,10 +1851,10 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar } if ((data->flag & ROTLIKE_Y) == 0) { - eul[1] = obeul[1]; + eul[1] = defeul[1]; } else { - if (data->flag & ROTLIKE_OFFSET) { + if (legacy_offset) { rotate_eulO(eul, rot_order, 'Y', obeul[1]); } @@ -1849,10 +1864,10 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar } if ((data->flag & ROTLIKE_Z) == 0) { - eul[2] = obeul[2]; + eul[2] = defeul[2]; } else { - if (data->flag & ROTLIKE_OFFSET) { + if (legacy_offset) { rotate_eulO(eul, rot_order, 'Z', obeul[2]); } @@ -1861,10 +1876,36 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar } } + /* Add the euler components together if needed. */ + if (data->mix_mode == ROTLIKE_MIX_ADD) { + add_v3_v3(eul, obeul); + } + /* Good to make eulers compatible again, * since we don't know how much they were changed above. */ compatible_eul(eul, obeul); - loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, rot_order); + eulO_to_mat3(newrot, eul, rot_order); + + /* Mix the rotation matrices: */ + switch (data->mix_mode) { + case ROTLIKE_MIX_REPLACE: + case ROTLIKE_MIX_OFFSET: + case ROTLIKE_MIX_ADD: + break; + + case ROTLIKE_MIX_BEFORE: + mul_m3_m3m3(newrot, newrot, oldrot); + break; + + case ROTLIKE_MIX_AFTER: + mul_m3_m3m3(newrot, oldrot, newrot); + break; + + default: + BLI_assert(false); + } + + loc_rot_size_to_mat4(cob->matrix, loc, newrot, size); } } diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 00c301a01bc..814b13fa47f 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -310,7 +310,7 @@ void mat4_to_size_fix_shear(float r[3], const float M[4][4]); void translate_m4(float mat[4][4], float tx, float ty, float tz); void rotate_m4(float mat[4][4], const char axis, const float angle); -void rescale_m4(float mat[4][4], float scale[3]); +void rescale_m4(float mat[4][4], const float scale[3]); void transform_pivot_set_m4(float mat[4][4], const float pivot[3]); void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]); @@ -320,6 +320,10 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]); +void loc_rot_size_to_mat4(float R[4][4], + const float loc[3], + const float rot[3][3], + const float size[3]); void loc_eul_size_to_mat4(float R[4][4], const float loc[3], const float eul[3], diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 7c1b44978e2..e9d196ccdbb 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -2164,7 +2164,7 @@ void rotate_m4(float mat[4][4], const char axis, const float angle) } /** Scale a matrix in-place. */ -void rescale_m4(float mat[4][4], float scale[3]) +void rescale_m4(float mat[4][4], const float scale[3]) { mul_v3_fl(mat[0], scale[0]); mul_v3_fl(mat[1], scale[1]); @@ -2359,6 +2359,20 @@ bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]) /** * Make a 4x4 matrix out of 3 transform components. * Matrices are made in the order: `scale * rot * loc` + */ +void loc_rot_size_to_mat4(float mat[4][4], + const float loc[3], + const float rot[3][3], + const float size[3]) +{ + copy_m4_m3(mat, rot); + rescale_m4(mat, size); + copy_v3_v3(mat[3], loc); +} + +/** + * Make a 4x4 matrix out of 3 transform components. + * Matrices are made in the order: `scale * rot * loc` * * TODO: need to have a version that allows for rotation order... */ diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 54d2bd8499f..0d108704b4e 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -727,6 +727,17 @@ static void do_version_constraints_copy_scale_power(ListBase *lb) } } +static void do_version_constraints_copy_rotation_mix_mode(ListBase *lb) +{ + for (bConstraint *con = lb->first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_ROTLIKE) { + bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data; + data->mix_mode = (data->flag & ROTLIKE_OFFSET) ? ROTLIKE_MIX_OFFSET : ROTLIKE_MIX_REPLACE; + data->flag &= ~ROTLIKE_OFFSET; + } + } +} + static void do_versions_seq_alloc_transform_and_crop(ListBase *seqbase) { for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) { @@ -3797,5 +3808,17 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) do_version_bones_inherit_scale(&arm->bonebase); } } + + /* Convert the Offset flag to the mix mode enum. */ + if (!DNA_struct_elem_find(fd->filesdna, "bRotateLikeConstraint", "char", "mix_mode")) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + do_version_constraints_copy_rotation_mix_mode(&ob->constraints); + if (ob->pose) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + do_version_constraints_copy_rotation_mix_mode(&pchan->constraints); + } + } + } + } } } diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 69bc6afd23f..14eee2318cd 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -1330,7 +1330,8 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list) /* CopyRot constraint only does this when rotating, and offset is on */ bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data; - if ((data->flag & ROTLIKE_OFFSET) && (t->mode == TFM_ROTATION)) { + if (ELEM(data->mix_mode, ROTLIKE_MIX_OFFSET, ROTLIKE_MIX_BEFORE) && + ELEM(t->mode, TFM_ROTATION)) { return true; } } diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 42d58cb34d0..a7f900ddc9b 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -272,7 +272,8 @@ typedef struct bRotateLikeConstraint { struct Object *tar; int flag; char euler_order; - char _pad[3]; + char mix_mode; + char _pad[2]; /** MAX_ID_NAME-2. */ char subtarget[64]; } bRotateLikeConstraint; @@ -747,9 +748,25 @@ typedef enum eCopyRotation_Flags { ROTLIKE_X_INVERT = (1 << 4), ROTLIKE_Y_INVERT = (1 << 5), ROTLIKE_Z_INVERT = (1 << 6), +#ifdef DNA_DEPRECATED ROTLIKE_OFFSET = (1 << 7), +#endif } eCopyRotation_Flags; +/* bRotateLikeConstraint.mix_mode */ +typedef enum eCopyRotation_MixMode { + /* Replace rotation channel values. */ + ROTLIKE_MIX_REPLACE = 0, + /* Legacy Offset mode - don't use. */ + ROTLIKE_MIX_OFFSET, + /* Add Euler components together. */ + ROTLIKE_MIX_ADD, + /* Multiply the copied rotation on the left. */ + ROTLIKE_MIX_BEFORE, + /* Multiply the copied rotation on the right. */ + ROTLIKE_MIX_AFTER, +} eCopyRotation_MixMode; + /* bLocateLikeConstraint.flag */ typedef enum eCopyLocation_Flags { LOCLIKE_X = (1 << 0), diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 05154dcc20e..79e38717569 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -530,6 +530,24 @@ static void rna_Constraint_ik_type_set(struct PointerRNA *ptr, int value) } } +/* DEPRECATED: use_offset replaced with mix_mode */ +static bool rna_Constraint_RotLike_use_offset_get(struct PointerRNA *ptr) +{ + bConstraint *con = ptr->data; + bRotateLikeConstraint *rotlike = con->data; + return rotlike->mix_mode != ROTLIKE_MIX_REPLACE; +} + +static void rna_Constraint_RotLike_use_offset_set(struct PointerRNA *ptr, bool value) +{ + bConstraint *con = ptr->data; + bRotateLikeConstraint *rotlike = con->data; + bool curval = (rotlike->mix_mode != ROTLIKE_MIX_REPLACE); + if (curval != value) { + rotlike->mix_mode = (value ? ROTLIKE_MIX_OFFSET : ROTLIKE_MIX_REPLACE); + } +} + static const EnumPropertyItem *rna_Constraint_owner_space_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), @@ -1298,6 +1316,28 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + static const EnumPropertyItem mix_mode_items[] = { + {ROTLIKE_MIX_REPLACE, "REPLACE", 0, "Replace", "Replace the original rotation with copied"}, + {ROTLIKE_MIX_ADD, "ADD", 0, "Add", "Add euler component values together"}, + {ROTLIKE_MIX_BEFORE, + "BEFORE", + 0, + "Before Original", + "Apply copied rotation before original, as if the constraint target is a parent"}, + {ROTLIKE_MIX_AFTER, + "AFTER", + 0, + "After Original", + "Apply copied rotation after original, as if the constraint target is a child"}, + {ROTLIKE_MIX_OFFSET, + "OFFSET", + 0, + "Offset (Legacy)", + "Combine rotations like the original Offset checkbox. Does not work well for " + "multiple axis rotations"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "CopyRotationConstraint", "Constraint"); RNA_def_struct_ui_text(srna, "Copy Rotation Constraint", "Copy the rotation of the target"); RNA_def_struct_sdna_from(srna, "bRotateLikeConstraint", "data"); @@ -1341,9 +1381,19 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Euler Order", "Explicitly specify the euler rotation order"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mix_mode"); + RNA_def_property_enum_items(prop, mix_mode_items); + RNA_def_property_ui_text( + prop, "Mix Mode", "Specify how the copied and existing rotations are combined"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + /* DEPRECATED: replaced with mix_mode */ prop = RNA_def_property(srna, "use_offset", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ROTLIKE_OFFSET); - RNA_def_property_ui_text(prop, "Offset", "Add original rotation into copied rotation"); + RNA_def_property_boolean_funcs( + prop, "rna_Constraint_RotLike_use_offset_get", "rna_Constraint_RotLike_use_offset_set"); + RNA_def_property_ui_text( + prop, "Offset", "DEPRECATED: Add original rotation into copied rotation"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); } |