Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/constraint.c
| Show First 20 Lines • Show All 535 Lines • ▼ Show 20 Lines | static void contarget_get_lattice_mat(Object *ob, const char *substring, float mat[4][4]) | ||||
| mul_v3_m4v3(tvec, ob->obmat, vec); | mul_v3_m4v3(tvec, ob->obmat, vec); | ||||
| /* copy new location to matrix */ | /* copy new location to matrix */ | ||||
| copy_v3_v3(mat[3], tvec); | copy_v3_v3(mat[3], tvec); | ||||
| } | } | ||||
| /* generic function to get the appropriate matrix for most target cases */ | /* generic function to get the appropriate matrix for most target cases */ | ||||
| /* The cases where the target can be object data have not been implemented */ | /* The cases where the target can be object data have not been implemented */ | ||||
| static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, short flag, float headtail) | static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, short flag, float headtail, bool full_bbone) | ||||
aligorith: I'm tempted to just include the full_bbone option as part of the `flags` arg, as a temporary… | |||||
| { | { | ||||
| /* Case OBJECT */ | /* Case OBJECT */ | ||||
| if (substring[0] == '\0') { | if (substring[0] == '\0') { | ||||
| copy_m4_m4(mat, ob->obmat); | copy_m4_m4(mat, ob->obmat); | ||||
| BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); | BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); | ||||
| } | } | ||||
| /* Case VERTEXGROUP */ | /* Case VERTEXGROUP */ | ||||
| /* Current method just takes the average location of all the points in the | /* Current method just takes the average location of all the points in the | ||||
| Show All 17 Lines | else { | ||||
| bPoseChannel *pchan; | bPoseChannel *pchan; | ||||
| pchan = BKE_pose_channel_find_name(ob->pose, substring); | pchan = BKE_pose_channel_find_name(ob->pose, substring); | ||||
| if (pchan) { | if (pchan) { | ||||
| /* Multiply the PoseSpace accumulation/final matrix for this | /* Multiply the PoseSpace accumulation/final matrix for this | ||||
| * PoseChannel by the Armature Object's Matrix to get a worldspace | * PoseChannel by the Armature Object's Matrix to get a worldspace | ||||
| * matrix. | * matrix. | ||||
| */ | */ | ||||
| if (headtail < 0.000001f) { | bool is_bbone = (pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE); | ||||
| if (headtail < 0.000001f && !(is_bbone && full_bbone)) { | |||||
| /* skip length interpolation if set to head */ | /* skip length interpolation if set to head */ | ||||
| mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); | mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); | ||||
| } | } | ||||
| else if ((pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE)) { | else if (is_bbone) { | ||||
| /* use point along bbone */ | /* use point along bbone */ | ||||
| Mat4 bbone[MAX_BBONE_SUBDIV]; | Mat4 bbone[MAX_BBONE_SUBDIV]; | ||||
| float tempmat[4][4]; | float tempmat[4][4]; | ||||
| float loc[3], fac; | float loc[3], fac; | ||||
| /* get bbone segments */ | /* get bbone segments */ | ||||
| b_bone_spline_setup(pchan, 0, bbone); | b_bone_spline_setup(pchan, 0, bbone); | ||||
| Show All 29 Lines | if (pchan) { | ||||
| copy_v3_v3(pt_b, bbone[index_b].mat[3]); | copy_v3_v3(pt_b, bbone[index_b].mat[3]); | ||||
| interp_v3_v3v3(pt, pt_a, pt_b, fac - floorf(fac)); | interp_v3_v3v3(pt, pt_a, pt_b, fac - floorf(fac)); | ||||
| /* move the point from bone local space to pose space... */ | /* move the point from bone local space to pose space... */ | ||||
| mul_v3_m4v3(loc, pchan->pose_mat, pt); | mul_v3_m4v3(loc, pchan->pose_mat, pt); | ||||
| } | } | ||||
| /* use interpolated distance for subtarget */ | /* apply full transformation of the segment if requested */ | ||||
| if (full_bbone) { | |||||
| int index = floorf(fac); | |||||
| CLAMP(index, 0, pchan->bone->segments-1); | |||||
| mul_m4_m4m4(tempmat, pchan->pose_mat, bbone[index].mat); | |||||
| } | |||||
| else { | |||||
| copy_m4_m4(tempmat, pchan->pose_mat); | copy_m4_m4(tempmat, pchan->pose_mat); | ||||
| } | |||||
| /* use interpolated distance for subtarget */ | |||||
| copy_v3_v3(tempmat[3], loc); | copy_v3_v3(tempmat[3], loc); | ||||
| mul_m4_m4m4(mat, ob->obmat, tempmat); | mul_m4_m4m4(mat, ob->obmat, tempmat); | ||||
| } | } | ||||
| else { | else { | ||||
| float tempmat[4][4], loc[3]; | float tempmat[4][4], loc[3]; | ||||
| /* interpolate along length of bone */ | /* interpolate along length of bone */ | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
| #endif | #endif | ||||
| /* This function should be used for the get_target_matrix member of all | /* This function should be used for the get_target_matrix member of all | ||||
| * constraints that are not picky about what happens to their target matrix. | * constraints that are not picky about what happens to their target matrix. | ||||
| */ | */ | ||||
| static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime)) | static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime)) | ||||
| { | { | ||||
| if (VALID_CONS_TARGET(ct)) | if (VALID_CONS_TARGET(ct)) | ||||
| constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail); | constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail, false); | ||||
| else if (ct) | |||||
| unit_m4(ct->matrix); | |||||
| } | |||||
| /* This is a variant that extracts full transformation from B-Bone segments. | |||||
| */ | |||||
| static void default_get_tarmat_full_bbone(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime)) | |||||
| { | |||||
| if (VALID_CONS_TARGET(ct)) | |||||
| constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail, true); | |||||
| else if (ct) | else if (ct) | ||||
| unit_m4(ct->matrix); | unit_m4(ct->matrix); | ||||
| } | } | ||||
| /* This following macro should be used for all standard single-target *_get_tars functions | /* This following macro should be used for all standard single-target *_get_tars functions | ||||
| * to save typing and reduce maintenance woes. | * to save typing and reduce maintenance woes. | ||||
| * (Hopefully all compilers will be happy with the lines with just a space on them. Those are | * (Hopefully all compilers will be happy with the lines with just a space on them. Those are | ||||
| * really just to help this code easier to read) | * really just to help this code easier to read) | ||||
| ▲ Show 20 Lines • Show All 454 Lines • ▼ Show 20 Lines | static void kinematic_flush_tars(bConstraint *con, ListBase *list, bool no_copy) | ||||
| } | } | ||||
| } | } | ||||
| static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) | static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) | ||||
| { | { | ||||
| bKinematicConstraint *data = con->data; | bKinematicConstraint *data = con->data; | ||||
| if (VALID_CONS_TARGET(ct)) | if (VALID_CONS_TARGET(ct)) | ||||
| constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail); | constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail, false); | ||||
| else if (ct) { | else if (ct) { | ||||
| if (data->flag & CONSTRAINT_IK_AUTO) { | if (data->flag & CONSTRAINT_IK_AUTO) { | ||||
| Object *ob = cob->ob; | Object *ob = cob->ob; | ||||
| if (ob == NULL) { | if (ob == NULL) { | ||||
| unit_m4(ct->matrix); | unit_m4(ct->matrix); | ||||
| } | } | ||||
| else { | else { | ||||
| ▲ Show 20 Lines • Show All 727 Lines • ▼ Show 20 Lines | static bConstraintTypeInfo CTI_TRANSLIKE = { | ||||
| "Copy Transforms", /* name */ | "Copy Transforms", /* name */ | ||||
| "bTransLikeConstraint", /* struct name */ | "bTransLikeConstraint", /* struct name */ | ||||
| NULL, /* free data */ | NULL, /* free data */ | ||||
| translike_id_looper, /* id looper */ | translike_id_looper, /* id looper */ | ||||
| NULL, /* copy data */ | NULL, /* copy data */ | ||||
| NULL, /* new data */ | NULL, /* new data */ | ||||
| translike_get_tars, /* get constraint targets */ | translike_get_tars, /* get constraint targets */ | ||||
| translike_flush_tars, /* flush constraint targets */ | translike_flush_tars, /* flush constraint targets */ | ||||
| default_get_tarmat, /* get target matrix */ | default_get_tarmat_full_bbone, /* get target matrix */ | ||||
| translike_evaluate /* evaluate */ | translike_evaluate /* evaluate */ | ||||
| }; | }; | ||||
| /* ---------- Maintain Volume ---------- */ | /* ---------- Maintain Volume ---------- */ | ||||
| static void samevolume_new_data(void *cdata) | static void samevolume_new_data(void *cdata) | ||||
| { | { | ||||
| bSameVolumeConstraint *data = (bSameVolumeConstraint *)cdata; | bSameVolumeConstraint *data = (bSameVolumeConstraint *)cdata; | ||||
| ▲ Show 20 Lines • Show All 123 Lines • ▼ Show 20 Lines | if (ct->tar->type == OB_CURVE) { | ||||
| BKE_displist_make_curveTypes(cob->scene, ct->tar, false); | BKE_displist_make_curveTypes(cob->scene, ct->tar, false); | ||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| /* firstly calculate the matrix the normal way, then let the py-function override | /* firstly calculate the matrix the normal way, then let the py-function override | ||||
| * this matrix if it needs to do so | * this matrix if it needs to do so | ||||
| */ | */ | ||||
| constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail); | constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail, true); | ||||
| /* only execute target calculation if allowed */ | /* only execute target calculation if allowed */ | ||||
| #ifdef WITH_PYTHON | #ifdef WITH_PYTHON | ||||
| if (G.f & G_SCRIPT_AUTOEXEC) | if (G.f & G_SCRIPT_AUTOEXEC) | ||||
| BPY_pyconstraint_target(data, ct); | BPY_pyconstraint_target(data, ct); | ||||
| #endif | #endif | ||||
| } | } | ||||
| else if (ct) | else if (ct) | ||||
| ▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | if (VALID_CONS_TARGET(ct)) { | ||||
| float tempmat[4][4], vec[3]; | float tempmat[4][4], vec[3]; | ||||
| float s, t; | float s, t; | ||||
| short axis; | short axis; | ||||
| /* initialize return matrix */ | /* initialize return matrix */ | ||||
| unit_m4(ct->matrix); | unit_m4(ct->matrix); | ||||
| /* get the transform matrix of the target */ | /* get the transform matrix of the target */ | ||||
| constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail); | constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail, false); | ||||
| /* determine where in transform range target is */ | /* determine where in transform range target is */ | ||||
| /* data->type is mapped as follows for backwards compatibility: | /* data->type is mapped as follows for backwards compatibility: | ||||
| * 00,01,02 - rotation (it used to be like this) | * 00,01,02 - rotation (it used to be like this) | ||||
| * 10,11,12 - scaling | * 10,11,12 - scaling | ||||
| * 20,21,22 - location | * 20,21,22 - location | ||||
| */ | */ | ||||
| if (data->type < 10) { | if (data->type < 10) { | ||||
| ▲ Show 20 Lines • Show All 2,867 Lines • Show Last 20 Lines | |||||
I'm tempted to just include the full_bbone option as part of the flags arg, as a temporary runtime-only flag that gets set where it's needed.
For example:
where this flag is defined in DNA_constraint_types.h -> eBConstraint_Flags as something like:
The only thing I'm not sure of atm is whether it's better to use this value (paving the way for future constraints to actually just expose such values directly), or to take over something like (1 << 15) or (1 << 31), which are usually reserved for the temp flags. On balance, it's probably better to use (1 << 11) then :)
The issue with adding the boolean arg as you've got it now is that it can quickly get confusing what exactly such "true" or "false" args mean when just scanning the code.