Transformation Constraint: implement a Mix Mode option.
Allow selecting how the new location/rotation/scale is combined with the existing transformation. This is most useful for rotation, which has multiple options, and scale, which previously could only replace.
This commit is contained in:
		@@ -761,6 +761,8 @@ class ConstraintButtonsPanel:
 | 
				
			|||||||
        sub.prop(con, "to_min_z" + ext, text="Min")
 | 
					        sub.prop(con, "to_min_z" + ext, text="Min")
 | 
				
			||||||
        sub.prop(con, "to_max_z" + ext, text="Max")
 | 
					        sub.prop(con, "to_max_z" + ext, text="Max")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        layout.prop(con, "mix_mode" + ext, text="Mix")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.space_template(layout, con)
 | 
					        self.space_template(layout, con)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def SHRINKWRAP(self, _context, layout, con):
 | 
					    def SHRINKWRAP(self, _context, layout, con):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3802,7 +3802,8 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
 | 
				
			|||||||
  /* only evaluate if there is a target */
 | 
					  /* only evaluate if there is a target */
 | 
				
			||||||
  if (VALID_CONS_TARGET(ct)) {
 | 
					  if (VALID_CONS_TARGET(ct)) {
 | 
				
			||||||
    float *from_min, *from_max, *to_min, *to_max;
 | 
					    float *from_min, *from_max, *to_min, *to_max;
 | 
				
			||||||
    float loc[3], eul[3], size[3];
 | 
					    float loc[3], rot[3][3], oldeul[3], size[3];
 | 
				
			||||||
 | 
					    float newloc[3], newrot[3][3], neweul[3], newsize[3];
 | 
				
			||||||
    float dbuf[4], sval[3];
 | 
					    float dbuf[4], sval[3];
 | 
				
			||||||
    float *const dvec = dbuf + 1;
 | 
					    float *const dvec = dbuf + 1;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
@@ -3844,9 +3845,7 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* extract components of owner's matrix */
 | 
					    /* extract components of owner's matrix */
 | 
				
			||||||
    copy_v3_v3(loc, cob->matrix[3]);
 | 
					    mat4_to_loc_rot_size(loc, rot, size, cob->matrix);
 | 
				
			||||||
    mat4_to_eulO(eul, rot_order, cob->matrix);
 | 
					 | 
				
			||||||
    mat4_to_size(size, cob->matrix);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* determine where in range current transforms lie */
 | 
					    /* determine where in range current transforms lie */
 | 
				
			||||||
    if (data->expo) {
 | 
					    if (data->expo) {
 | 
				
			||||||
@@ -3878,18 +3877,42 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
 | 
				
			|||||||
        to_min = data->to_min_scale;
 | 
					        to_min = data->to_min_scale;
 | 
				
			||||||
        to_max = data->to_max_scale;
 | 
					        to_max = data->to_max_scale;
 | 
				
			||||||
        for (i = 0; i < 3; i++) {
 | 
					        for (i = 0; i < 3; i++) {
 | 
				
			||||||
          /* multiply with original scale (so that it can still be scaled) */
 | 
					          newsize[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
 | 
				
			||||||
          /* size[i] *= to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); */
 | 
					        }
 | 
				
			||||||
          /* Stay absolute, else it breaks existing rigs... sigh. */
 | 
					        switch (data->mix_mode_scale) {
 | 
				
			||||||
          size[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
 | 
					          case TRANS_MIXSCALE_MULTIPLY:
 | 
				
			||||||
 | 
					            mul_v3_v3(size, newsize);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case TRANS_MIXSCALE_REPLACE:
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            copy_v3_v3(size, newsize);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      case TRANS_ROTATION:
 | 
					      case TRANS_ROTATION:
 | 
				
			||||||
        to_min = data->to_min_rot;
 | 
					        to_min = data->to_min_rot;
 | 
				
			||||||
        to_max = data->to_max_rot;
 | 
					        to_max = data->to_max_rot;
 | 
				
			||||||
        for (i = 0; i < 3; i++) {
 | 
					        for (i = 0; i < 3; i++) {
 | 
				
			||||||
          /* add to original rotation (so that it can still be rotated) */
 | 
					          neweul[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
 | 
				
			||||||
          eul[i] += to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
 | 
					        }
 | 
				
			||||||
 | 
					        switch (data->mix_mode_rot) {
 | 
				
			||||||
 | 
					          case TRANS_MIXROT_REPLACE:
 | 
				
			||||||
 | 
					            eulO_to_mat3(rot, neweul, rot_order);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case TRANS_MIXROT_BEFORE:
 | 
				
			||||||
 | 
					            eulO_to_mat3(newrot, neweul, rot_order);
 | 
				
			||||||
 | 
					            mul_m3_m3m3(rot, newrot, rot);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case TRANS_MIXROT_AFTER:
 | 
				
			||||||
 | 
					            eulO_to_mat3(newrot, neweul, rot_order);
 | 
				
			||||||
 | 
					            mul_m3_m3m3(rot, rot, newrot);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case TRANS_MIXROT_ADD:
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            mat3_to_eulO(oldeul, rot_order, rot);
 | 
				
			||||||
 | 
					            add_v3_v3(neweul, oldeul);
 | 
				
			||||||
 | 
					            eulO_to_mat3(rot, neweul, rot_order);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      case TRANS_LOCATION:
 | 
					      case TRANS_LOCATION:
 | 
				
			||||||
@@ -3897,14 +3920,22 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
 | 
				
			|||||||
        to_min = data->to_min;
 | 
					        to_min = data->to_min;
 | 
				
			||||||
        to_max = data->to_max;
 | 
					        to_max = data->to_max;
 | 
				
			||||||
        for (i = 0; i < 3; i++) {
 | 
					        for (i = 0; i < 3; i++) {
 | 
				
			||||||
          /* add to original location (so that it can still be moved) */
 | 
					          newloc[i] = (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])));
 | 
				
			||||||
          loc[i] += (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])));
 | 
					        }
 | 
				
			||||||
 | 
					        switch (data->mix_mode_loc) {
 | 
				
			||||||
 | 
					          case TRANS_MIXLOC_REPLACE:
 | 
				
			||||||
 | 
					            copy_v3_v3(loc, newloc);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case TRANS_MIXLOC_ADD:
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            add_v3_v3(loc, newloc);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* apply to matrix */
 | 
					    /* apply to matrix */
 | 
				
			||||||
    loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, rot_order);
 | 
					    loc_rot_size_to_mat4(cob->matrix, loc, rot, size);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1348,11 +1348,13 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list)
 | 
				
			|||||||
          /* Transform constraint needs it for rotation at least (r.57309),
 | 
					          /* Transform constraint needs it for rotation at least (r.57309),
 | 
				
			||||||
           * but doing so when translating may also mess things up [#36203]
 | 
					           * but doing so when translating may also mess things up [#36203]
 | 
				
			||||||
           */
 | 
					           */
 | 
				
			||||||
 | 
					          bTransformConstraint *data = (bTransformConstraint *)con->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (t->mode == TFM_ROTATION) {
 | 
					          if (data->to == TRANS_ROTATION) {
 | 
				
			||||||
            return true;
 | 
					            if (t->mode == TFM_ROTATION && data->mix_mode_rot == TRANS_MIXROT_BEFORE) {
 | 
				
			||||||
 | 
					              return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          /* ??? (t->mode == TFM_SCALE) ? */
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -450,7 +450,12 @@ typedef struct bTransformConstraint {
 | 
				
			|||||||
  /** Output euler order override. */
 | 
					  /** Output euler order override. */
 | 
				
			||||||
  char to_euler_order;
 | 
					  char to_euler_order;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  char _pad[6];
 | 
					  /** Mixing modes for location, rotation, and scale. */
 | 
				
			||||||
 | 
					  char mix_mode_loc;
 | 
				
			||||||
 | 
					  char mix_mode_rot;
 | 
				
			||||||
 | 
					  char mix_mode_scale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  char _pad[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** From_min/max defines range of target transform. */
 | 
					  /** From_min/max defines range of target transform. */
 | 
				
			||||||
  float from_min[3];
 | 
					  float from_min[3];
 | 
				
			||||||
@@ -809,6 +814,34 @@ typedef enum eTransform_ToFrom {
 | 
				
			|||||||
  TRANS_SCALE = 2,
 | 
					  TRANS_SCALE = 2,
 | 
				
			||||||
} eTransform_ToFrom;
 | 
					} eTransform_ToFrom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* bTransformConstraint.mix_mode_loc */
 | 
				
			||||||
 | 
					typedef enum eTransform_MixModeLoc {
 | 
				
			||||||
 | 
					  /* Add component values together (default). */
 | 
				
			||||||
 | 
					  TRANS_MIXLOC_ADD = 0,
 | 
				
			||||||
 | 
					  /* Replace component values. */
 | 
				
			||||||
 | 
					  TRANS_MIXLOC_REPLACE,
 | 
				
			||||||
 | 
					} eTransform_MixModeLoc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* bTransformConstraint.mix_mode_rot */
 | 
				
			||||||
 | 
					typedef enum eTransform_MixModeRot {
 | 
				
			||||||
 | 
					  /* Add component values together (default). */
 | 
				
			||||||
 | 
					  TRANS_MIXROT_ADD = 0,
 | 
				
			||||||
 | 
					  /* Replace component values. */
 | 
				
			||||||
 | 
					  TRANS_MIXROT_REPLACE,
 | 
				
			||||||
 | 
					  /* Multiply the generated rotation on the left. */
 | 
				
			||||||
 | 
					  TRANS_MIXROT_BEFORE,
 | 
				
			||||||
 | 
					  /* Multiply the generated rotation on the right. */
 | 
				
			||||||
 | 
					  TRANS_MIXROT_AFTER,
 | 
				
			||||||
 | 
					} eTransform_MixModeRot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* bTransformConstraint.mix_mode_scale */
 | 
				
			||||||
 | 
					typedef enum eTransform_MixModeScale {
 | 
				
			||||||
 | 
					  /* Replace component values (default). */
 | 
				
			||||||
 | 
					  TRANS_MIXSCALE_REPLACE = 0,
 | 
				
			||||||
 | 
					  /* Multiply component values together. */
 | 
				
			||||||
 | 
					  TRANS_MIXSCALE_MULTIPLY,
 | 
				
			||||||
 | 
					} eTransform_MixModeScale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* bSameVolumeConstraint.free_axis */
 | 
					/* bSameVolumeConstraint.free_axis */
 | 
				
			||||||
typedef enum eSameVolume_Axis {
 | 
					typedef enum eSameVolume_Axis {
 | 
				
			||||||
  SAMEVOL_X = 0,
 | 
					  SAMEVOL_X = 0,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1934,6 +1934,34 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
 | 
				
			|||||||
      {0, NULL, 0, NULL, NULL},
 | 
					      {0, NULL, 0, NULL, NULL},
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static const EnumPropertyItem mix_mode_loc_items[] = {
 | 
				
			||||||
 | 
					      {TRANS_MIXLOC_REPLACE, "REPLACE", 0, "Replace", "Replace component values"},
 | 
				
			||||||
 | 
					      {TRANS_MIXLOC_ADD, "ADD", 0, "Add", "Add component values together"},
 | 
				
			||||||
 | 
					      {0, NULL, 0, NULL, NULL},
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static const EnumPropertyItem mix_mode_rot_items[] = {
 | 
				
			||||||
 | 
					      {TRANS_MIXROT_REPLACE, "REPLACE", 0, "Replace", "Replace component values"},
 | 
				
			||||||
 | 
					      {TRANS_MIXROT_ADD, "ADD", 0, "Add", "Add component values together"},
 | 
				
			||||||
 | 
					      {TRANS_MIXROT_BEFORE,
 | 
				
			||||||
 | 
					       "BEFORE",
 | 
				
			||||||
 | 
					       0,
 | 
				
			||||||
 | 
					       "Before Original",
 | 
				
			||||||
 | 
					       "Apply new rotation before original, as if it was on a parent"},
 | 
				
			||||||
 | 
					      {TRANS_MIXROT_AFTER,
 | 
				
			||||||
 | 
					       "AFTER",
 | 
				
			||||||
 | 
					       0,
 | 
				
			||||||
 | 
					       "After Original",
 | 
				
			||||||
 | 
					       "Apply new rotation after original, as if it was on a child"},
 | 
				
			||||||
 | 
					      {0, NULL, 0, NULL, NULL},
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static const EnumPropertyItem mix_mode_scale_items[] = {
 | 
				
			||||||
 | 
					      {TRANS_MIXSCALE_REPLACE, "REPLACE", 0, "Replace", "Replace component values"},
 | 
				
			||||||
 | 
					      {TRANS_MIXSCALE_MULTIPLY, "MULTIPLY", 0, "Multiply", "Multiply component values together"},
 | 
				
			||||||
 | 
					      {0, NULL, 0, NULL, NULL},
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  srna = RNA_def_struct(brna, "TransformConstraint", "Constraint");
 | 
					  srna = RNA_def_struct(brna, "TransformConstraint", "Constraint");
 | 
				
			||||||
  RNA_def_struct_ui_text(
 | 
					  RNA_def_struct_ui_text(
 | 
				
			||||||
      srna, "Transformation Constraint", "Map transformations of the target to the object");
 | 
					      srna, "Transformation Constraint", "Map transformations of the target to the object");
 | 
				
			||||||
@@ -2066,6 +2094,13 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
 | 
				
			|||||||
  RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
 | 
					  RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
 | 
				
			||||||
  RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 | 
					  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_loc");
 | 
				
			||||||
 | 
					  RNA_def_property_enum_items(prop, mix_mode_loc_items);
 | 
				
			||||||
 | 
					  RNA_def_property_ui_text(
 | 
				
			||||||
 | 
					      prop, "Location Mix Mode", "Specify how to combine the new location with original");
 | 
				
			||||||
 | 
					  RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Rot */
 | 
					  /* Rot */
 | 
				
			||||||
  prop = RNA_def_property(srna, "from_min_x_rot", PROP_FLOAT, PROP_ANGLE);
 | 
					  prop = RNA_def_property(srna, "from_min_x_rot", PROP_FLOAT, PROP_ANGLE);
 | 
				
			||||||
  RNA_def_property_float_sdna(prop, NULL, "from_min_rot[0]");
 | 
					  RNA_def_property_float_sdna(prop, NULL, "from_min_rot[0]");
 | 
				
			||||||
@@ -2139,6 +2174,13 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
 | 
				
			|||||||
  RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
 | 
					  RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
 | 
				
			||||||
  RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 | 
					  RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  prop = RNA_def_property(srna, "mix_mode_rot", PROP_ENUM, PROP_NONE);
 | 
				
			||||||
 | 
					  RNA_def_property_enum_sdna(prop, NULL, "mix_mode_rot");
 | 
				
			||||||
 | 
					  RNA_def_property_enum_items(prop, mix_mode_rot_items);
 | 
				
			||||||
 | 
					  RNA_def_property_ui_text(
 | 
				
			||||||
 | 
					      prop, "Rotation Mix Mode", "Specify how to combine the new rotation with original");
 | 
				
			||||||
 | 
					  RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Scale */
 | 
					  /* Scale */
 | 
				
			||||||
  prop = RNA_def_property(srna, "from_min_x_scale", PROP_FLOAT, PROP_NONE);
 | 
					  prop = RNA_def_property(srna, "from_min_x_scale", PROP_FLOAT, PROP_NONE);
 | 
				
			||||||
  RNA_def_property_float_sdna(prop, NULL, "from_min_scale[0]");
 | 
					  RNA_def_property_float_sdna(prop, NULL, "from_min_scale[0]");
 | 
				
			||||||
@@ -2211,6 +2253,13 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
 | 
				
			|||||||
  RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 10, 3);
 | 
					  RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 10, 3);
 | 
				
			||||||
  RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
 | 
					  RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
 | 
				
			||||||
  RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 | 
					  RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  prop = RNA_def_property(srna, "mix_mode_scale", PROP_ENUM, PROP_NONE);
 | 
				
			||||||
 | 
					  RNA_def_property_enum_sdna(prop, NULL, "mix_mode_scale");
 | 
				
			||||||
 | 
					  RNA_def_property_enum_items(prop, mix_mode_scale_items);
 | 
				
			||||||
 | 
					  RNA_def_property_ui_text(
 | 
				
			||||||
 | 
					      prop, "Scale Mix Mode", "Specify how to combine the new scale with original");
 | 
				
			||||||
 | 
					  RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void rna_def_constraint_location_limit(BlenderRNA *brna)
 | 
					static void rna_def_constraint_location_limit(BlenderRNA *brna)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user