diff options
-rw-r--r-- | release/scripts/ui/properties_object_constraint.py | 18 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 113 | ||||
-rw-r--r-- | source/blender/editors/object/object_constraint.c | 17 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_constraint_types.h | 54 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_constraint.c | 60 |
6 files changed, 257 insertions, 6 deletions
diff --git a/release/scripts/ui/properties_object_constraint.py b/release/scripts/ui/properties_object_constraint.py index f53bac05a7c..11527ad9bda 100644 --- a/release/scripts/ui/properties_object_constraint.py +++ b/release/scripts/ui/properties_object_constraint.py @@ -76,7 +76,7 @@ class ConstraintButtonsPanel(bpy.types.Panel): else: layout.prop_object(con, "subtarget", con.target.data, "bones", text="") - if con.type in ('COPY_LOCATION', 'STRETCH_TO', 'TRACK_TO'): + if con.type in ('COPY_LOCATION', 'STRETCH_TO', 'TRACK_TO', 'PIVOT'): row = layout.row() row.label(text="Head/Tail:") row.prop(con, "head_tail", text="") @@ -730,6 +730,22 @@ class ConstraintButtonsPanel(bpy.types.Panel): col.prop(con, "xz_scaling_mode", text="") col.prop(con, "use_curve_radius") + def PIVOT(self, context, layout, con, wide_ui): + self.target_template(layout, con, wide_ui) + + if con.target: + col = layout.column() + col.prop(con, "offset", text="Pivot Offset") + else: + col = layout.column() + col.prop(con, "use_relative_position") + if con.use_relative_position: + col.prop(con, "offset", text="Relative Pivot Point") + else: + col.prop(con, "offset", text="Absolute Pivot Point") + + col = layout.column() + col.prop(con, "enabled_rotation_range", text="Pivot When") class OBJECT_PT_constraints(ConstraintButtonsPanel): bl_label = "Object Constraints" diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index a3f1cb0cb0c..1a8d665a91d 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -3831,6 +3831,118 @@ static bConstraintTypeInfo CTI_SPLINEIK = { NULL /* evaluate - solved as separate loop */ }; +/* ----------- Pivot ------------- */ + +static void pivotcon_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata) +{ + bPivotConstraint *data= con->data; + + /* target only */ + func(con, (ID**)&data->tar, userdata); +} + +static int pivotcon_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bPivotConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; + } + + return 0; +} + +static void pivotcon_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bPivotConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void pivotcon_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bPivotConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + float pivot[3], vec[3]; + float rotMat[3][3]; + + /* firstly, check if pivoting should take place based on the current rotation */ + if (data->rotAxis != PIVOTCON_AXIS_NONE) { + float rot[3]; + + /* extract euler-rotation of target */ + mat4_to_eulO(rot, cob->rotOrder, cob->matrix); + + /* check which range might be violated */ + if (data->rotAxis < PIVOTCON_AXIS_X) { + /* negative rotations (data->rotAxis = 0 -> 2) */ + if (rot[data->rotAxis] > 0.0f) + return; + } + else { + /* positive rotations (data->rotAxis = 3 -> 5 */ + if (rot[data->rotAxis - PIVOTCON_AXIS_X] < 0.0f) + return; + } + } + + /* find the pivot-point to use */ + if (VALID_CONS_TARGET(ct)) { + /* apply offset to target location */ + add_v3_v3v3(pivot, ct->matrix[3], data->offset); + } + else { + /* no targets to worry about... */ + if ((data->flag & PIVOTCON_FLAG_OFFSET_ABS) == 0) { + /* offset is relative to owner */ + add_v3_v3v3(pivot, cob->matrix[3], data->offset); + } + else { + /* directly use the 'offset' specified as an absolute position instead */ + VECCOPY(pivot, data->offset); + } + } + + /* get rotation matrix representing the rotation of the owner */ + // TODO: perhaps we might want to include scaling based on the pivot too? + copy_m3_m4(rotMat, cob->matrix); + normalize_m3(rotMat); + + /* perform the pivoting... */ + /* 1. take the vector from owner to the pivot */ + sub_v3_v3v3(vec, pivot, cob->matrix[3]); + /* 2. rotate this vector by the rotation of the object... */ + mul_m3_v3(rotMat, vec); + /* 3. make the rotation in terms of the pivot now */ + add_v3_v3v3(cob->matrix[3], pivot, vec); +} + + +static bConstraintTypeInfo CTI_PIVOT = { + CONSTRAINT_TYPE_PIVOT, /* type */ + sizeof(bPivotConstraint), /* size */ + "Pivot", /* name */ + "bPivotConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + pivotcon_id_looper, /* id looper */ + NULL, /* copy data */ + NULL, /* new data */ // XXX: might be needed to get 'normal' pivot behaviour... + pivotcon_get_tars, /* get constraint targets */ + pivotcon_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + pivotcon_evaluate /* evaluate */ +}; + /* ************************* Constraints Type-Info *************************** */ /* All of the constraints api functions use bConstraintTypeInfo structs to carry out * and operations that involve constraint specific code. @@ -3867,6 +3979,7 @@ static void constraints_init_typeinfo () { constraintsTypeInfo[22]= &CTI_SPLINEIK; /* Spline IK Constraint */ constraintsTypeInfo[23]= &CTI_TRANSLIKE; /* Copy Transforms Constraint */ constraintsTypeInfo[24]= &CTI_SAMEVOL; /* Maintain Volume Constraint */ + constraintsTypeInfo[25]= &CTI_PIVOT; /* Pivot Constraint */ } /* This function should be used for getting the appropriate type-info when only diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 9163baf606f..eaabcd866cd 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -322,6 +322,23 @@ static void test_constraints (Object *owner, bPoseChannel *pchan) /* targets have already been checked for this */ continue; } + else if (curcon->type == CONSTRAINT_TYPE_PIVOT) { + bPivotConstraint *data = curcon->data; + + /* target doesn't have to exist, but if it is non-null, it must exist! */ + if (data->tar && exist_object(data->tar)==0) { + data->tar = NULL; + curcon->flag |= CONSTRAINT_DISABLE; + } + else if (data->tar == owner) { + if (!get_named_bone(get_armature(owner), data->subtarget)) { + curcon->flag |= CONSTRAINT_DISABLE; + } + } + + /* targets have already been checked for this */ + continue; + } else if (curcon->type == CONSTRAINT_TYPE_ACTION) { bActionConstraint *data = curcon->data; diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 6c7bda171eb..00694a7ea1f 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -174,6 +174,7 @@ typedef struct bSplineIKConstraint { /* Single-target subobject constraints --------------------- */ + /* Track To Constraint */ typedef struct bTrackToConstraint { Object *tar; @@ -336,6 +337,24 @@ typedef struct bTransformConstraint { float to_max[3]; } bTransformConstraint; +/* Pivot Constraint */ +typedef struct bPivotConstraint { + /* Pivot Point: + * Either target object + offset, or just offset is used + */ + Object *tar; /* target object (optional) */ + char subtarget[32]; /* subtarget name (optional) */ + float offset[3]; /* offset from the target to use, regardless of whether it exists */ + + /* Rotation-driven activation: + * This option provides easier one-stop setups for footrolls + */ + short rotAxis; /* rotation axes to consider for this (ePivotConstraint_Axis) */ + + /* General flags */ + short flag; /* ePivotConstraint_Flag */ +} bPivotConstraint; + /* transform limiting constraints - zero target ---------------------------- */ /* Limit Location Constraint */ typedef struct bLocLimitConstraint { @@ -419,6 +438,7 @@ typedef enum eBConstraint_Types { CONSTRAINT_TYPE_SPLINEIK, /* Spline-IK - Align 'n' bones to a curve */ CONSTRAINT_TYPE_TRANSLIKE, /* Copy transform matrix */ CONSTRAINT_TYPE_SAMEVOL, /* Maintain volume during scaling */ + CONSTRAINT_TYPE_PIVOT, /* Pivot Constraint */ /* NOTE: no constraints are allowed to be added after this */ NUM_CONSTRAINT_TYPES @@ -469,11 +489,6 @@ typedef enum eConstraintChannel_Flags { /* -------------------------------------- */ -/** - * The flags for ROTLIKE, LOCLIKE and SIZELIKE should be kept identical - * (that is, same effect, different name). It simplifies the Python API access a lot. - */ - /* bRotateLikeConstraint.flag */ typedef enum eCopyRotation_Flags { ROTLIKE_X = (1<<0), @@ -688,6 +703,35 @@ typedef enum eChildOf_Flags { CHILDOF_SIZEZ = (1<<8), } eChildOf_Flags; +/* Pivot Constraint */ + /* Restrictions for Pivot Constraint axis to consider for enabling constraint */ +typedef enum ePivotConstraint_Axis { + /* do not consider this activity-clamping */ + PIVOTCON_AXIS_NONE = -1, + + /* consider -ve x-axis rotations */ + PIVOTCON_AXIS_X_NEG, + /* consider -ve y-axis rotations */ + PIVOTCON_AXIS_Y_NEG, + /* consider -ve z-axis rotations */ + PIVOTCON_AXIS_Z_NEG, + + /* consider +ve x-axis rotations */ + PIVOTCON_AXIS_X, + /* consider +ve y-axis rotations */ + PIVOTCON_AXIS_Y, + /* consider +ve z-axis rotations */ + PIVOTCON_AXIS_Z, +} ePivotConstraint_Axis; + + /* settings for Pivot Constraint in general */ +typedef enum ePivotConstraint_Flag { + /* offset is to be interpreted as being a fixed-point in space */ + PIVOTCON_FLAG_OFFSET_ABS = (1<<0), + /* rotation-based activation uses negative rotation to drive result */ + PIVOTCON_FLAG_ROTACT_NEG = (1<<1), +} ePivotConstraint_Flag; + /* Rigid-Body Constraint */ #define CONSTRAINT_DRAW_PIVOT 0x40 #define CONSTRAINT_DISABLE_LINKED_COLLISION 0x80 diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index f9802e558bb..3badc401514 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -356,6 +356,7 @@ extern StructRNA RNA_SPHFluidSettings; extern StructRNA RNA_ParticleSystem; extern StructRNA RNA_ParticleSystemModifier; extern StructRNA RNA_ParticleTarget; +extern StructRNA RNA_PivotConstraint; extern StructRNA RNA_PluginSequence; extern StructRNA RNA_PluginTexture; extern StructRNA RNA_PointCache; diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index b4ae49ae2f4..b1c5cac1865 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -67,6 +67,7 @@ EnumPropertyItem constraint_type_items[] ={ {CONSTRAINT_TYPE_RIGIDBODYJOINT, "RIGID_BODY_JOINT", ICON_CONSTRAINT_DATA, "Rigid Body Joint", ""}, {CONSTRAINT_TYPE_PYTHON, "SCRIPT", ICON_CONSTRAINT_DATA, "Script", ""}, {CONSTRAINT_TYPE_SHRINKWRAP, "SHRINKWRAP", ICON_CONSTRAINT_DATA, "Shrinkwrap", ""}, + {CONSTRAINT_TYPE_PIVOT, "PIVOT", ICON_CONSTRAINT_DATA, "Pivot", ""}, {0, NULL, 0, NULL, NULL}}; EnumPropertyItem space_pchan_items[] = { @@ -157,6 +158,8 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr) return &RNA_SplineIKConstraint; case CONSTRAINT_TYPE_TRANSLIKE: return &RNA_CopyTransformsConstraint; + case CONSTRAINT_TYPE_PIVOT: + return &RNA_PivotConstraint; default: return &RNA_UnknownType; } @@ -1839,6 +1842,62 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); } +static void rna_def_constraint_pivot(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem pivot_rotAxis_items[] = { + {PIVOTCON_AXIS_NONE, "ALWAYS_ACTIVE", 0, "Always", ""}, + {PIVOTCON_AXIS_X_NEG, "NX", 0, "-X Rot", ""}, + {PIVOTCON_AXIS_Y_NEG, "NY", 0, "-Y Rot", ""}, + {PIVOTCON_AXIS_Z_NEG, "NZ", 0, "-Z Rot", ""}, + {PIVOTCON_AXIS_X, "X", 0, "X Rot", ""}, + {PIVOTCON_AXIS_Y, "Y", 0, "Y Rot", ""}, + {PIVOTCON_AXIS_Z, "Z", 0, "Z Rot", ""}, + {0, NULL, 0, NULL, NULL}}; + + srna= RNA_def_struct(brna, "PivotConstraint", "Constraint"); + RNA_def_struct_ui_text(srna, "Pivot Constraint", "Rotate around a different point"); + + prop= RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, "bConstraint", "headtail"); + RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1"); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + + RNA_def_struct_sdna_from(srna, "bPivotConstraint", "data"); + + /* target-defined pivot */ + prop= RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "tar"); + RNA_def_property_ui_text(prop, "Target", "Target Object, defining the position of the pivot when defined"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update"); + + prop= RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "subtarget"); + RNA_def_property_ui_text(prop, "Sub-Target", ""); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update"); + + /* pivot offset */ + prop= RNA_def_property(srna, "use_relative_position", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", PIVOTCON_FLAG_OFFSET_ABS); + RNA_def_property_ui_text(prop, "Use Relative Offset", "Offset will be an absolute point in space instead of relative to the target"); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + + prop= RNA_def_property(srna, "offset", PROP_FLOAT, PROP_XYZ); + RNA_def_property_float_sdna(prop, NULL, "offset"); + RNA_def_property_ui_text(prop, "Offset", "Offset of pivot from target (when set), or from owner's location (when Fixed Position is off), or the absolute pivot point"); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + + /* rotation-based activation */ + prop= RNA_def_property(srna, "enabled_rotation_range", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "rotAxis"); + RNA_def_property_enum_items(prop, pivot_rotAxis_items); + RNA_def_property_ui_text(prop, "Enabled Rotation Range", "Rotation range on which pivoting should occur"); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); +} + /* base struct for constraints */ void RNA_def_constraint(BlenderRNA *brna) { @@ -1943,6 +2002,7 @@ void RNA_def_constraint(BlenderRNA *brna) rna_def_constraint_shrinkwrap(brna); rna_def_constraint_damped_track(brna); rna_def_constraint_spline_ik(brna); + rna_def_constraint_pivot(brna); } #endif |