diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/blenkernel/intern/constraint.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/blenkernel/intern/constraint.c')
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 8053 |
1 files changed, 4129 insertions, 3924 deletions
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 1ba29424def..114bf5ec1e6 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -21,7 +21,6 @@ * \ingroup bke */ - #include <stdio.h> #include <stddef.h> #include <string.h> @@ -52,7 +51,6 @@ #include "DNA_tracking_types.h" #include "DNA_movieclip_types.h" - #include "BKE_action.h" #include "BKE_anim.h" /* for the curve calculation part */ #include "BKE_armature.h" @@ -105,7 +103,10 @@ static CLG_LogRef LOG = {"bke.constraint"}; static void damptrack_do_transform(float matrix[4][4], const float tarvec[3], int track_axis); -static bConstraint *constraint_find_original(Object *ob, bPoseChannel *pchan, bConstraint *con, Object **r_orig_ob); +static bConstraint *constraint_find_original(Object *ob, + bPoseChannel *pchan, + bConstraint *con, + Object **r_orig_ob); static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bConstraint *con); /* -------------- Naming -------------- */ @@ -113,136 +114,133 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon /* Find the first available, non-duplicate name for a given constraint */ void BKE_constraint_unique_name(bConstraint *con, ListBase *list) { - BLI_uniquename(list, con, DATA_("Const"), '.', offsetof(bConstraint, name), sizeof(con->name)); + BLI_uniquename(list, con, DATA_("Const"), '.', offsetof(bConstraint, name), sizeof(con->name)); } /* ----------------- Evaluation Loop Preparation --------------- */ /* package an object/bone for use in constraint evaluation */ /* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */ -bConstraintOb *BKE_constraints_make_evalob(Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype) -{ - bConstraintOb *cob; - - /* create regardless of whether we have any data! */ - cob = MEM_callocN(sizeof(bConstraintOb), "bConstraintOb"); - - /* for system time, part of deglobalization, code nicer later with local time (ton) */ - cob->scene = scene; - cob->depsgraph = depsgraph; - - /* based on type of available data */ - switch (datatype) { - case CONSTRAINT_OBTYPE_OBJECT: - { - /* disregard subdata... calloc should set other values right */ - if (ob) { - cob->ob = ob; - cob->type = datatype; - - if (cob->ob->rotmode > 0) { - /* Should be some kind of Euler order, so use it */ - /* NOTE: Versions <= 2.76 assumed that "default" order - * would always get used, so we may seem some rig - * breakage as a result. However, this change here - * is needed to fix T46599 - */ - cob->rotOrder = ob->rotmode; - } - else { - /* Quats/Axis-Angle, so Eulers should just use default order */ - cob->rotOrder = EULER_ORDER_DEFAULT; - } - copy_m4_m4(cob->matrix, ob->obmat); - } - else - unit_m4(cob->matrix); - - copy_m4_m4(cob->startmat, cob->matrix); - break; - } - case CONSTRAINT_OBTYPE_BONE: - { - /* only set if we have valid bone, otherwise default */ - if (ob && subdata) { - cob->ob = ob; - cob->pchan = (bPoseChannel *)subdata; - cob->type = datatype; - - if (cob->pchan->rotmode > 0) { - /* should be some type of Euler order */ - cob->rotOrder = cob->pchan->rotmode; - } - else { - /* Quats, so eulers should just use default order */ - cob->rotOrder = EULER_ORDER_DEFAULT; - } - - /* matrix in world-space */ - mul_m4_m4m4(cob->matrix, ob->obmat, cob->pchan->pose_mat); - } - else - unit_m4(cob->matrix); - - copy_m4_m4(cob->startmat, cob->matrix); - break; - } - default: /* other types not yet handled */ - unit_m4(cob->matrix); - unit_m4(cob->startmat); - break; - } - - return cob; +bConstraintOb *BKE_constraints_make_evalob( + Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype) +{ + bConstraintOb *cob; + + /* create regardless of whether we have any data! */ + cob = MEM_callocN(sizeof(bConstraintOb), "bConstraintOb"); + + /* for system time, part of deglobalization, code nicer later with local time (ton) */ + cob->scene = scene; + cob->depsgraph = depsgraph; + + /* based on type of available data */ + switch (datatype) { + case CONSTRAINT_OBTYPE_OBJECT: { + /* disregard subdata... calloc should set other values right */ + if (ob) { + cob->ob = ob; + cob->type = datatype; + + if (cob->ob->rotmode > 0) { + /* Should be some kind of Euler order, so use it */ + /* NOTE: Versions <= 2.76 assumed that "default" order + * would always get used, so we may seem some rig + * breakage as a result. However, this change here + * is needed to fix T46599 + */ + cob->rotOrder = ob->rotmode; + } + else { + /* Quats/Axis-Angle, so Eulers should just use default order */ + cob->rotOrder = EULER_ORDER_DEFAULT; + } + copy_m4_m4(cob->matrix, ob->obmat); + } + else + unit_m4(cob->matrix); + + copy_m4_m4(cob->startmat, cob->matrix); + break; + } + case CONSTRAINT_OBTYPE_BONE: { + /* only set if we have valid bone, otherwise default */ + if (ob && subdata) { + cob->ob = ob; + cob->pchan = (bPoseChannel *)subdata; + cob->type = datatype; + + if (cob->pchan->rotmode > 0) { + /* should be some type of Euler order */ + cob->rotOrder = cob->pchan->rotmode; + } + else { + /* Quats, so eulers should just use default order */ + cob->rotOrder = EULER_ORDER_DEFAULT; + } + + /* matrix in world-space */ + mul_m4_m4m4(cob->matrix, ob->obmat, cob->pchan->pose_mat); + } + else + unit_m4(cob->matrix); + + copy_m4_m4(cob->startmat, cob->matrix); + break; + } + default: /* other types not yet handled */ + unit_m4(cob->matrix); + unit_m4(cob->startmat); + break; + } + + return cob; } /* cleanup after constraint evaluation */ void BKE_constraints_clear_evalob(bConstraintOb *cob) { - float delta[4][4], imat[4][4]; - - /* prevent crashes */ - if (cob == NULL) - return; - - /* calculate delta of constraints evaluation */ - invert_m4_m4(imat, cob->startmat); - /* XXX This would seem to be in wrong order. However, it does not work in 'right' order - would be nice to - * understand why premul is needed here instead of usual postmul? - * In any case, we **do not get a delta** here (e.g. startmat & matrix having same location, still gives - * a 'delta' with non-null translation component :/ ).*/ - mul_m4_m4m4(delta, cob->matrix, imat); - - /* copy matrices back to source */ - switch (cob->type) { - case CONSTRAINT_OBTYPE_OBJECT: - { - /* cob->ob might not exist! */ - if (cob->ob) { - /* copy new ob-matrix back to owner */ - copy_m4_m4(cob->ob->obmat, cob->matrix); - - /* copy inverse of delta back to owner */ - invert_m4_m4(cob->ob->constinv, delta); - } - break; - } - case CONSTRAINT_OBTYPE_BONE: - { - /* cob->ob or cob->pchan might not exist */ - if (cob->ob && cob->pchan) { - /* copy new pose-matrix back to owner */ - mul_m4_m4m4(cob->pchan->pose_mat, cob->ob->imat, cob->matrix); - - /* copy inverse of delta back to owner */ - invert_m4_m4(cob->pchan->constinv, delta); - } - break; - } - } - - /* free tempolary struct */ - MEM_freeN(cob); + float delta[4][4], imat[4][4]; + + /* prevent crashes */ + if (cob == NULL) + return; + + /* calculate delta of constraints evaluation */ + invert_m4_m4(imat, cob->startmat); + /* XXX This would seem to be in wrong order. However, it does not work in 'right' order - would be nice to + * understand why premul is needed here instead of usual postmul? + * In any case, we **do not get a delta** here (e.g. startmat & matrix having same location, still gives + * a 'delta' with non-null translation component :/ ).*/ + mul_m4_m4m4(delta, cob->matrix, imat); + + /* copy matrices back to source */ + switch (cob->type) { + case CONSTRAINT_OBTYPE_OBJECT: { + /* cob->ob might not exist! */ + if (cob->ob) { + /* copy new ob-matrix back to owner */ + copy_m4_m4(cob->ob->obmat, cob->matrix); + + /* copy inverse of delta back to owner */ + invert_m4_m4(cob->ob->constinv, delta); + } + break; + } + case CONSTRAINT_OBTYPE_BONE: { + /* cob->ob or cob->pchan might not exist */ + if (cob->ob && cob->pchan) { + /* copy new pose-matrix back to owner */ + mul_m4_m4m4(cob->pchan->pose_mat, cob->ob->imat, cob->matrix); + + /* copy inverse of delta back to owner */ + invert_m4_m4(cob->pchan->constinv, delta); + } + break; + } + } + + /* free tempolary struct */ + MEM_freeN(cob); } /* -------------- Space-Conversion API -------------- */ @@ -252,138 +250,140 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob) * For now, this is only implemented for Objects and PoseChannels. */ void BKE_constraint_mat_convertspace( - Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale) -{ - float diff_mat[4][4]; - float imat[4][4]; - - /* prevent crashes in these unlikely events */ - if (ob == NULL || mat == NULL) return; - /* optimize trick - check if need to do anything */ - if (from == to) return; - - /* are we dealing with pose-channels or objects */ - if (pchan) { - /* pose channels */ - switch (from) { - case CONSTRAINT_SPACE_WORLD: /* ---------- FROM WORLDSPACE ---------- */ - { - /* world to pose */ - invert_m4_m4(imat, ob->obmat); - mul_m4_m4m4(mat, imat, mat); - - /* use pose-space as stepping stone for other spaces... */ - if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) { - /* call self with slightly different values */ - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); - } - break; - } - case CONSTRAINT_SPACE_POSE: /* ---------- FROM POSESPACE ---------- */ - { - /* pose to world */ - if (to == CONSTRAINT_SPACE_WORLD) { - mul_m4_m4m4(mat, ob->obmat, mat); - } - /* pose to local */ - else if (to == CONSTRAINT_SPACE_LOCAL) { - if (pchan->bone) { - BKE_armature_mat_pose_to_bone(pchan, mat, mat); - } - } - /* pose to local with parent */ - else if (to == CONSTRAINT_SPACE_PARLOCAL) { - if (pchan->bone) { - invert_m4_m4(imat, pchan->bone->arm_mat); - mul_m4_m4m4(mat, imat, mat); - } - } - break; - } - case CONSTRAINT_SPACE_LOCAL: /* ------------ FROM LOCALSPACE --------- */ - { - /* local to pose - do inverse procedure that was done for pose to local */ - if (pchan->bone) { - /* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */ - BKE_armature_mat_bone_to_pose(pchan, mat, mat); - } - - /* use pose-space as stepping stone for other spaces */ - if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) { - /* call self with slightly different values */ - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); - } - break; - } - case CONSTRAINT_SPACE_PARLOCAL: /* -------------- FROM LOCAL WITH PARENT ---------- */ - { - /* local + parent to pose */ - if (pchan->bone) { - mul_m4_m4m4(mat, pchan->bone->arm_mat, mat); - } - - /* use pose-space as stepping stone for other spaces */ - if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) { - /* call self with slightly different values */ - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); - } - break; - } - } - } - else { - /* objects */ - if (from == CONSTRAINT_SPACE_WORLD && to == CONSTRAINT_SPACE_LOCAL) { - /* check if object has a parent */ - if (ob->parent) { - /* 'subtract' parent's effects from owner */ - mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); - invert_m4_m4_safe(imat, diff_mat); - mul_m4_m4m4(mat, imat, mat); - } - else { - /* Local space in this case will have to be defined as local to the owner's - * transform-property-rotated axes. So subtract this rotation component. - */ - /* XXX This is actually an ugly hack, local space of a parent-less object *is* the same as - * global space! - * Think what we want actually here is some kind of 'Final Space', i.e. once transformations - * are applied - users are often confused about this too, this is not consistent with bones - * local space either... Meh :| - * --mont29 - */ - BKE_object_to_mat4(ob, diff_mat); - if (!keep_scale) { - normalize_m4(diff_mat); - } - zero_v3(diff_mat[3]); - - invert_m4_m4_safe(imat, diff_mat); - mul_m4_m4m4(mat, imat, mat); - } - } - else if (from == CONSTRAINT_SPACE_LOCAL && to == CONSTRAINT_SPACE_WORLD) { - /* check that object has a parent - otherwise this won't work */ - if (ob->parent) { - /* 'add' parent's effect back to owner */ - mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); - mul_m4_m4m4(mat, diff_mat, mat); - } - else { - /* Local space in this case will have to be defined as local to the owner's - * transform-property-rotated axes. So add back this rotation component. - */ - /* XXX See comment above for world->local case... */ - BKE_object_to_mat4(ob, diff_mat); - if (!keep_scale) { - normalize_m4(diff_mat); - } - zero_v3(diff_mat[3]); - - mul_m4_m4m4(mat, diff_mat, mat); - } - } - } + Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale) +{ + float diff_mat[4][4]; + float imat[4][4]; + + /* prevent crashes in these unlikely events */ + if (ob == NULL || mat == NULL) + return; + /* optimize trick - check if need to do anything */ + if (from == to) + return; + + /* are we dealing with pose-channels or objects */ + if (pchan) { + /* pose channels */ + switch (from) { + case CONSTRAINT_SPACE_WORLD: /* ---------- FROM WORLDSPACE ---------- */ + { + /* world to pose */ + invert_m4_m4(imat, ob->obmat); + mul_m4_m4m4(mat, imat, mat); + + /* use pose-space as stepping stone for other spaces... */ + if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) { + /* call self with slightly different values */ + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); + } + break; + } + case CONSTRAINT_SPACE_POSE: /* ---------- FROM POSESPACE ---------- */ + { + /* pose to world */ + if (to == CONSTRAINT_SPACE_WORLD) { + mul_m4_m4m4(mat, ob->obmat, mat); + } + /* pose to local */ + else if (to == CONSTRAINT_SPACE_LOCAL) { + if (pchan->bone) { + BKE_armature_mat_pose_to_bone(pchan, mat, mat); + } + } + /* pose to local with parent */ + else if (to == CONSTRAINT_SPACE_PARLOCAL) { + if (pchan->bone) { + invert_m4_m4(imat, pchan->bone->arm_mat); + mul_m4_m4m4(mat, imat, mat); + } + } + break; + } + case CONSTRAINT_SPACE_LOCAL: /* ------------ FROM LOCALSPACE --------- */ + { + /* local to pose - do inverse procedure that was done for pose to local */ + if (pchan->bone) { + /* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */ + BKE_armature_mat_bone_to_pose(pchan, mat, mat); + } + + /* use pose-space as stepping stone for other spaces */ + if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) { + /* call self with slightly different values */ + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); + } + break; + } + case CONSTRAINT_SPACE_PARLOCAL: /* -------------- FROM LOCAL WITH PARENT ---------- */ + { + /* local + parent to pose */ + if (pchan->bone) { + mul_m4_m4m4(mat, pchan->bone->arm_mat, mat); + } + + /* use pose-space as stepping stone for other spaces */ + if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) { + /* call self with slightly different values */ + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); + } + break; + } + } + } + else { + /* objects */ + if (from == CONSTRAINT_SPACE_WORLD && to == CONSTRAINT_SPACE_LOCAL) { + /* check if object has a parent */ + if (ob->parent) { + /* 'subtract' parent's effects from owner */ + mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); + invert_m4_m4_safe(imat, diff_mat); + mul_m4_m4m4(mat, imat, mat); + } + else { + /* Local space in this case will have to be defined as local to the owner's + * transform-property-rotated axes. So subtract this rotation component. + */ + /* XXX This is actually an ugly hack, local space of a parent-less object *is* the same as + * global space! + * Think what we want actually here is some kind of 'Final Space', i.e. once transformations + * are applied - users are often confused about this too, this is not consistent with bones + * local space either... Meh :| + * --mont29 + */ + BKE_object_to_mat4(ob, diff_mat); + if (!keep_scale) { + normalize_m4(diff_mat); + } + zero_v3(diff_mat[3]); + + invert_m4_m4_safe(imat, diff_mat); + mul_m4_m4m4(mat, imat, mat); + } + } + else if (from == CONSTRAINT_SPACE_LOCAL && to == CONSTRAINT_SPACE_WORLD) { + /* check that object has a parent - otherwise this won't work */ + if (ob->parent) { + /* 'add' parent's effect back to owner */ + mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); + mul_m4_m4m4(mat, diff_mat, mat); + } + else { + /* Local space in this case will have to be defined as local to the owner's + * transform-property-rotated axes. So add back this rotation component. + */ + /* XXX See comment above for world->local case... */ + BKE_object_to_mat4(ob, diff_mat); + if (!keep_scale) { + normalize_m4(diff_mat); + } + zero_v3(diff_mat[3]); + + mul_m4_m4m4(mat, diff_mat, mat); + } + } + } } /* ------------ General Target Matrix Tools ---------- */ @@ -391,246 +391,259 @@ void BKE_constraint_mat_convertspace( /* function that sets the given matrix based on given vertex group in mesh */ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[4][4]) { - /* when not in EditMode, use the 'final' evaluated mesh, depsgraph - * ensures we build with CD_MDEFORMVERT layer - */ - Mesh *me_eval = ob->runtime.mesh_eval; - BMEditMesh *em = BKE_editmesh_from_object(ob); - float plane[3]; - float imat[3][3], tmat[3][3]; - const int defgroup = defgroup_name_index(ob, substring); - - /* initialize target matrix using target matrix */ - copy_m4_m4(mat, ob->obmat); - - /* get index of vertex group */ - if (defgroup == -1) { - return; - } - - float vec[3] = {0.0f, 0.0f, 0.0f}; - float normal[3] = {0.0f, 0.0f, 0.0f}; - float weightsum = 0.0f; - if (me_eval) { - MDeformVert *dvert = CustomData_get_layer(&me_eval->vdata, CD_MDEFORMVERT); - int numVerts = me_eval->totvert; - - /* check that dvert is a valid pointers (just in case) */ - if (dvert) { - MDeformVert *dv = dvert; - MVert *mv = me_eval->mvert; - - /* get the average of all verts with that are in the vertex-group */ - for (int i = 0; i < numVerts; i++, dv++, mv++) { - MDeformWeight *dw = defvert_find_index(dv, defgroup); - - if (dw && dw->weight > 0.0f) { - float nor[3]; - normal_short_to_float_v3(nor, mv->no); - madd_v3_v3fl(vec, mv->co, dw->weight); - madd_v3_v3fl(normal, nor, dw->weight); - weightsum += dw->weight; - } - } - } - } - else if (em) { - if (CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) { - BMVert *v; - BMIter iter; - - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - MDeformVert *dv = CustomData_bmesh_get(&em->bm->vdata, v->head.data, CD_MDEFORMVERT); - MDeformWeight *dw = defvert_find_index(dv, defgroup); - - if (dw && dw->weight > 0.0f) { - madd_v3_v3fl(vec, v->co, dw->weight); - madd_v3_v3fl(normal, v->no, dw->weight); - weightsum += dw->weight; - } - } - } - } - else { - /* No valid edit or evaluated mesh, just abort. */ - return; - } - - /* calculate averages of normal and coordinates */ - if (weightsum > 0) { - mul_v3_fl(vec, 1.0f / weightsum); - mul_v3_fl(normal, 1.0f / weightsum); - } - - /* derive the rotation from the average normal: - * - code taken from transform_gizmo.c, - * calc_gizmo_stats, V3D_ORIENT_NORMAL case - */ - /* we need the transpose of the inverse for a normal... */ - copy_m3_m4(imat, ob->obmat); - - invert_m3_m3(tmat, imat); - transpose_m3(tmat); - mul_m3_v3(tmat, normal); - - normalize_v3(normal); - copy_v3_v3(plane, tmat[1]); - - cross_v3_v3v3(mat[0], normal, plane); - if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) { - copy_v3_v3(plane, tmat[0]); - cross_v3_v3v3(mat[0], normal, plane); - } - - copy_v3_v3(mat[2], normal); - cross_v3_v3v3(mat[1], mat[2], mat[0]); - - normalize_m4(mat); - - /* apply the average coordinate as the new location */ - mul_v3_m4v3(mat[3], ob->obmat, vec); + /* when not in EditMode, use the 'final' evaluated mesh, depsgraph + * ensures we build with CD_MDEFORMVERT layer + */ + Mesh *me_eval = ob->runtime.mesh_eval; + BMEditMesh *em = BKE_editmesh_from_object(ob); + float plane[3]; + float imat[3][3], tmat[3][3]; + const int defgroup = defgroup_name_index(ob, substring); + + /* initialize target matrix using target matrix */ + copy_m4_m4(mat, ob->obmat); + + /* get index of vertex group */ + if (defgroup == -1) { + return; + } + + float vec[3] = {0.0f, 0.0f, 0.0f}; + float normal[3] = {0.0f, 0.0f, 0.0f}; + float weightsum = 0.0f; + if (me_eval) { + MDeformVert *dvert = CustomData_get_layer(&me_eval->vdata, CD_MDEFORMVERT); + int numVerts = me_eval->totvert; + + /* check that dvert is a valid pointers (just in case) */ + if (dvert) { + MDeformVert *dv = dvert; + MVert *mv = me_eval->mvert; + + /* get the average of all verts with that are in the vertex-group */ + for (int i = 0; i < numVerts; i++, dv++, mv++) { + MDeformWeight *dw = defvert_find_index(dv, defgroup); + + if (dw && dw->weight > 0.0f) { + float nor[3]; + normal_short_to_float_v3(nor, mv->no); + madd_v3_v3fl(vec, mv->co, dw->weight); + madd_v3_v3fl(normal, nor, dw->weight); + weightsum += dw->weight; + } + } + } + } + else if (em) { + if (CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) { + BMVert *v; + BMIter iter; + + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + MDeformVert *dv = CustomData_bmesh_get(&em->bm->vdata, v->head.data, CD_MDEFORMVERT); + MDeformWeight *dw = defvert_find_index(dv, defgroup); + + if (dw && dw->weight > 0.0f) { + madd_v3_v3fl(vec, v->co, dw->weight); + madd_v3_v3fl(normal, v->no, dw->weight); + weightsum += dw->weight; + } + } + } + } + else { + /* No valid edit or evaluated mesh, just abort. */ + return; + } + + /* calculate averages of normal and coordinates */ + if (weightsum > 0) { + mul_v3_fl(vec, 1.0f / weightsum); + mul_v3_fl(normal, 1.0f / weightsum); + } + + /* derive the rotation from the average normal: + * - code taken from transform_gizmo.c, + * calc_gizmo_stats, V3D_ORIENT_NORMAL case + */ + /* we need the transpose of the inverse for a normal... */ + copy_m3_m4(imat, ob->obmat); + + invert_m3_m3(tmat, imat); + transpose_m3(tmat); + mul_m3_v3(tmat, normal); + + normalize_v3(normal); + copy_v3_v3(plane, tmat[1]); + + cross_v3_v3v3(mat[0], normal, plane); + if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) { + copy_v3_v3(plane, tmat[0]); + cross_v3_v3v3(mat[0], normal, plane); + } + + copy_v3_v3(mat[2], normal); + cross_v3_v3v3(mat[1], mat[2], mat[0]); + + normalize_m4(mat); + + /* apply the average coordinate as the new location */ + mul_v3_m4v3(mat[3], ob->obmat, vec); } /* function that sets the given matrix based on given vertex group in lattice */ static void contarget_get_lattice_mat(Object *ob, const char *substring, float mat[4][4]) { - Lattice *lt = (Lattice *)ob->data; - - DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL; - const float *co = dl ? dl->verts : NULL; - BPoint *bp = lt->def; - - MDeformVert *dv = lt->dvert; - int tot_verts = lt->pntsu * lt->pntsv * lt->pntsw; - float vec[3] = {0.0f, 0.0f, 0.0f}, tvec[3]; - int grouped = 0; - int i, n; - const int defgroup = defgroup_name_index(ob, substring); - - /* initialize target matrix using target matrix */ - copy_m4_m4(mat, ob->obmat); - - /* get index of vertex group */ - if (defgroup == -1) return; - if (dv == NULL) return; - - /* 1. Loop through control-points checking if in nominated vertex-group. - * 2. If it is, add it to vec to find the average point. - */ - for (i = 0; i < tot_verts; i++, dv++) { - for (n = 0; n < dv->totweight; n++) { - MDeformWeight *dw = defvert_find_index(dv, defgroup); - if (dw && dw->weight > 0.0f) { - /* copy coordinates of point to temporary vector, then add to find average */ - memcpy(tvec, co ? co : bp->vec, 3 * sizeof(float)); - - add_v3_v3(vec, tvec); - grouped++; - } - } - - /* advance pointer to coordinate data */ - if (co) co += 3; - else bp++; - } - - /* find average location, then multiply by ob->obmat to find world-space location */ - if (grouped) - mul_v3_fl(vec, 1.0f / grouped); - mul_v3_m4v3(tvec, ob->obmat, vec); - - /* copy new location to matrix */ - copy_v3_v3(mat[3], tvec); + Lattice *lt = (Lattice *)ob->data; + + DispList *dl = ob->runtime.curve_cache ? + BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : + NULL; + const float *co = dl ? dl->verts : NULL; + BPoint *bp = lt->def; + + MDeformVert *dv = lt->dvert; + int tot_verts = lt->pntsu * lt->pntsv * lt->pntsw; + float vec[3] = {0.0f, 0.0f, 0.0f}, tvec[3]; + int grouped = 0; + int i, n; + const int defgroup = defgroup_name_index(ob, substring); + + /* initialize target matrix using target matrix */ + copy_m4_m4(mat, ob->obmat); + + /* get index of vertex group */ + if (defgroup == -1) + return; + if (dv == NULL) + return; + + /* 1. Loop through control-points checking if in nominated vertex-group. + * 2. If it is, add it to vec to find the average point. + */ + for (i = 0; i < tot_verts; i++, dv++) { + for (n = 0; n < dv->totweight; n++) { + MDeformWeight *dw = defvert_find_index(dv, defgroup); + if (dw && dw->weight > 0.0f) { + /* copy coordinates of point to temporary vector, then add to find average */ + memcpy(tvec, co ? co : bp->vec, 3 * sizeof(float)); + + add_v3_v3(vec, tvec); + grouped++; + } + } + + /* advance pointer to coordinate data */ + if (co) + co += 3; + else + bp++; + } + + /* find average location, then multiply by ob->obmat to find world-space location */ + if (grouped) + mul_v3_fl(vec, 1.0f / grouped); + mul_v3_m4v3(tvec, ob->obmat, vec); + + /* copy new location to matrix */ + copy_v3_v3(mat[3], tvec); } /* generic function to get the appropriate matrix for most target cases */ /* 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) -{ - /* Case OBJECT */ - if (substring[0] == '\0') { - copy_m4_m4(mat, ob->obmat); - BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); - } - /* Case VERTEXGROUP */ - /* Current method just takes the average location of all the points in the - * VertexGroup, and uses that as the location value of the targets. Where - * possible, the orientation will also be calculated, by calculating an - * 'average' vertex normal, and deriving the rotation from that. - * - * NOTE: EditMode is not currently supported, and will most likely remain that - * way as constraints can only really affect things on object/bone level. - */ - else if (ob->type == OB_MESH) { - contarget_get_mesh_mat(ob, substring, mat); - BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); - } - else if (ob->type == OB_LATTICE) { - contarget_get_lattice_mat(ob, substring, mat); - BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); - } - /* Case BONE */ - else { - bPoseChannel *pchan; - - pchan = BKE_pose_channel_find_name(ob->pose, substring); - if (pchan) { - /* Multiply the PoseSpace accumulation/final matrix for this - * PoseChannel by the Armature Object's Matrix to get a worldspace - * matrix. - */ - bool is_bbone = (pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE); - bool full_bbone = (flag & CONSTRAINT_BBONE_SHAPE_FULL) != 0; - - if (headtail < 0.000001f && !(is_bbone && full_bbone)) { - /* skip length interpolation if set to head */ - mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); - } - else if (is_bbone && pchan->bone->segments == pchan->runtime.bbone_segments) { - /* use point along bbone */ - Mat4 *bbone = pchan->runtime.bbone_pose_mats; - float tempmat[4][4]; - float loc[3], fac; - int index; - - /* figure out which segment(s) the headtail value falls in */ - BKE_pchan_bbone_deform_segment_index(pchan, headtail, &index, &fac); - - /* apply full transformation of the segment if requested */ - if (full_bbone) { - interp_m4_m4m4(tempmat, bbone[index].mat, bbone[index + 1].mat, fac); - - mul_m4_m4m4(tempmat, pchan->pose_mat, tempmat); - } - /* only interpolate location */ - else { - interp_v3_v3v3(loc, bbone[index].mat[3], bbone[index + 1].mat[3], fac); - - copy_m4_m4(tempmat, pchan->pose_mat); - mul_v3_m4v3(tempmat[3], pchan->pose_mat, loc); - } - - mul_m4_m4m4(mat, ob->obmat, tempmat); - } - else { - float tempmat[4][4], loc[3]; - - /* interpolate along length of bone */ - interp_v3_v3v3(loc, pchan->pose_head, pchan->pose_tail, headtail); - - /* use interpolated distance for subtarget */ - copy_m4_m4(tempmat, pchan->pose_mat); - copy_v3_v3(tempmat[3], loc); - - mul_m4_m4m4(mat, ob->obmat, tempmat); - } - } - else - copy_m4_m4(mat, ob->obmat); - - /* convert matrix space as required */ - BKE_constraint_mat_convertspace(ob, pchan, mat, from, to, false); - } +static void constraint_target_to_mat4(Object *ob, + const char *substring, + float mat[4][4], + short from, + short to, + short flag, + float headtail) +{ + /* Case OBJECT */ + if (substring[0] == '\0') { + copy_m4_m4(mat, ob->obmat); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); + } + /* Case VERTEXGROUP */ + /* Current method just takes the average location of all the points in the + * VertexGroup, and uses that as the location value of the targets. Where + * possible, the orientation will also be calculated, by calculating an + * 'average' vertex normal, and deriving the rotation from that. + * + * NOTE: EditMode is not currently supported, and will most likely remain that + * way as constraints can only really affect things on object/bone level. + */ + else if (ob->type == OB_MESH) { + contarget_get_mesh_mat(ob, substring, mat); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); + } + else if (ob->type == OB_LATTICE) { + contarget_get_lattice_mat(ob, substring, mat); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); + } + /* Case BONE */ + else { + bPoseChannel *pchan; + + pchan = BKE_pose_channel_find_name(ob->pose, substring); + if (pchan) { + /* Multiply the PoseSpace accumulation/final matrix for this + * PoseChannel by the Armature Object's Matrix to get a worldspace + * matrix. + */ + bool is_bbone = (pchan->bone) && (pchan->bone->segments > 1) && + (flag & CONSTRAINT_BBONE_SHAPE); + bool full_bbone = (flag & CONSTRAINT_BBONE_SHAPE_FULL) != 0; + + if (headtail < 0.000001f && !(is_bbone && full_bbone)) { + /* skip length interpolation if set to head */ + mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); + } + else if (is_bbone && pchan->bone->segments == pchan->runtime.bbone_segments) { + /* use point along bbone */ + Mat4 *bbone = pchan->runtime.bbone_pose_mats; + float tempmat[4][4]; + float loc[3], fac; + int index; + + /* figure out which segment(s) the headtail value falls in */ + BKE_pchan_bbone_deform_segment_index(pchan, headtail, &index, &fac); + + /* apply full transformation of the segment if requested */ + if (full_bbone) { + interp_m4_m4m4(tempmat, bbone[index].mat, bbone[index + 1].mat, fac); + + mul_m4_m4m4(tempmat, pchan->pose_mat, tempmat); + } + /* only interpolate location */ + else { + interp_v3_v3v3(loc, bbone[index].mat[3], bbone[index + 1].mat[3], fac); + + copy_m4_m4(tempmat, pchan->pose_mat); + mul_v3_m4v3(tempmat[3], pchan->pose_mat, loc); + } + + mul_m4_m4m4(mat, ob->obmat, tempmat); + } + else { + float tempmat[4][4], loc[3]; + + /* interpolate along length of bone */ + interp_v3_v3v3(loc, pchan->pose_head, pchan->pose_tail, headtail); + + /* use interpolated distance for subtarget */ + copy_m4_m4(tempmat, pchan->pose_mat); + copy_v3_v3(tempmat[3], loc); + + mul_m4_m4m4(mat, ob->obmat, tempmat); + } + } + else + copy_m4_m4(mat, ob->obmat); + + /* convert matrix space as required */ + BKE_constraint_mat_convertspace(ob, pchan, mat, from, to, false); + } } /* ************************* Specific Constraints ***************************** */ @@ -652,40 +665,60 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m */ #if 0 static bConstraintTypeInfo CTI_CONSTRNAME = { - CONSTRAINT_TYPE_CONSTRNAME, /* type */ - sizeof(bConstrNameConstraint), /* size */ - "ConstrName", /* name */ - "bConstrNameConstraint", /* struct name */ - constrname_free, /* free data */ - constrname_id_looper, /* id looper */ - constrname_copy, /* copy data */ - constrname_new_data, /* new data */ - constrname_get_tars, /* get constraint targets */ - constrname_flush_tars, /* flush constraint targets */ - constrname_get_tarmat, /* get target matrix */ - constrname_evaluate, /* evaluate */ + CONSTRAINT_TYPE_CONSTRNAME, /* type */ + sizeof(bConstrNameConstraint), /* size */ + "ConstrName", /* name */ + "bConstrNameConstraint", /* struct name */ + constrname_free, /* free data */ + constrname_id_looper, /* id looper */ + constrname_copy, /* copy data */ + constrname_new_data, /* new data */ + constrname_get_tars, /* get constraint targets */ + constrname_flush_tars, /* flush constraint targets */ + constrname_get_tarmat, /* get target matrix */ + constrname_evaluate, /* evaluate */ }; #endif /* 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. */ -static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), 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); - else if (ct) - unit_m4(ct->matrix); +static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), + 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); + 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(struct Depsgraph *UNUSED(depsgraph), 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 | CONSTRAINT_BBONE_SHAPE_FULL, con->headtail); - else if (ct) - unit_m4(ct->matrix); +static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), + 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 | CONSTRAINT_BBONE_SHAPE_FULL, + con->headtail); + else if (ct) + unit_m4(ct->matrix); } /* This following macro should be used for all standard single-target *_get_tars functions @@ -695,32 +728,33 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), b */ // TODO: cope with getting rotation order... #define SINGLETARGET_GET_TARS(con, datatar, datasubtarget, ct, list) \ - { \ - ct = MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \ - \ - ct->tar = datatar; \ - BLI_strncpy(ct->subtarget, datasubtarget, sizeof(ct->subtarget)); \ - ct->space = con->tarspace; \ - ct->flag = CONSTRAINT_TAR_TEMP; \ - \ - if (ct->tar) { \ - if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) { \ - bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); \ - ct->type = CONSTRAINT_OBTYPE_BONE; \ - ct->rotOrder = (pchan) ? (pchan->rotmode) : EULER_ORDER_DEFAULT; \ - } \ - else if (OB_TYPE_SUPPORT_VGROUP(ct->tar->type) && (ct->subtarget[0])) { \ - ct->type = CONSTRAINT_OBTYPE_VERT; \ - ct->rotOrder = EULER_ORDER_DEFAULT; \ - } \ - else { \ - ct->type = CONSTRAINT_OBTYPE_OBJECT; \ - ct->rotOrder = ct->tar->rotmode; \ - } \ - } \ - \ - BLI_addtail(list, ct); \ - } (void)0 + { \ + ct = MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \ +\ + ct->tar = datatar; \ + BLI_strncpy(ct->subtarget, datasubtarget, sizeof(ct->subtarget)); \ + ct->space = con->tarspace; \ + ct->flag = CONSTRAINT_TAR_TEMP; \ +\ + if (ct->tar) { \ + if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) { \ + bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); \ + ct->type = CONSTRAINT_OBTYPE_BONE; \ + ct->rotOrder = (pchan) ? (pchan->rotmode) : EULER_ORDER_DEFAULT; \ + } \ + else if (OB_TYPE_SUPPORT_VGROUP(ct->tar->type) && (ct->subtarget[0])) { \ + ct->type = CONSTRAINT_OBTYPE_VERT; \ + ct->rotOrder = EULER_ORDER_DEFAULT; \ + } \ + else { \ + ct->type = CONSTRAINT_OBTYPE_OBJECT; \ + ct->rotOrder = ct->tar->rotmode; \ + } \ + } \ +\ + BLI_addtail(list, ct); \ + } \ + (void)0 /* This following macro should be used for all standard single-target *_get_tars functions * to save typing and reduce maintenance woes. It does not do the subtarget related operations @@ -729,17 +763,19 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), b */ // TODO: cope with getting rotation order... #define SINGLETARGETNS_GET_TARS(con, datatar, ct, list) \ - { \ - ct = MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \ - \ - ct->tar = datatar; \ - ct->space = con->tarspace; \ - ct->flag = CONSTRAINT_TAR_TEMP; \ - \ - if (ct->tar) ct->type = CONSTRAINT_OBTYPE_OBJECT; \ - \ - BLI_addtail(list, ct); \ - } (void)0 + { \ + ct = MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \ +\ + ct->tar = datatar; \ + ct->space = con->tarspace; \ + ct->flag = CONSTRAINT_TAR_TEMP; \ +\ + if (ct->tar) \ + ct->type = CONSTRAINT_OBTYPE_OBJECT; \ +\ + BLI_addtail(list, ct); \ + } \ + (void)0 /* This following macro should be used for all standard single-target *_flush_tars functions * to save typing and reduce maintenance woes. @@ -748,19 +784,20 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), b * really just to help this code easier to read) */ #define SINGLETARGET_FLUSH_TARS(con, datatar, datasubtarget, ct, list, no_copy) \ - { \ - if (ct) { \ - bConstraintTarget *ctn = ct->next; \ - if (no_copy == 0) { \ - datatar = ct->tar; \ - BLI_strncpy(datasubtarget, ct->subtarget, sizeof(datasubtarget)); \ - con->tarspace = (char)ct->space; \ - } \ - \ - BLI_freelinkN(list, ct); \ - ct = ctn; \ - } \ - } (void)0 + { \ + if (ct) { \ + bConstraintTarget *ctn = ct->next; \ + if (no_copy == 0) { \ + datatar = ct->tar; \ + BLI_strncpy(datasubtarget, ct->subtarget, sizeof(datasubtarget)); \ + con->tarspace = (char)ct->space; \ + } \ +\ + BLI_freelinkN(list, ct); \ + ct = ctn; \ + } \ + } \ + (void)0 /* This following macro should be used for all standard single-target *_flush_tars functions * to save typing and reduce maintenance woes. It does not do the subtarget related operations. @@ -769,3856 +806,3982 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), b * really just to help this code easier to read) */ #define SINGLETARGETNS_FLUSH_TARS(con, datatar, ct, list, no_copy) \ - { \ - if (ct) { \ - bConstraintTarget *ctn = ct->next; \ - if (no_copy == 0) { \ - datatar = ct->tar; \ - con->tarspace = (char)ct->space; \ - } \ - \ - BLI_freelinkN(list, ct); \ - ct = ctn; \ - } \ - } (void)0 + { \ + if (ct) { \ + bConstraintTarget *ctn = ct->next; \ + if (no_copy == 0) { \ + datatar = ct->tar; \ + con->tarspace = (char)ct->space; \ + } \ +\ + BLI_freelinkN(list, ct); \ + ct = ctn; \ + } \ + } \ + (void)0 /* --------- ChildOf Constraint ------------ */ static void childof_new_data(void *cdata) { - bChildOfConstraint *data = (bChildOfConstraint *)cdata; + bChildOfConstraint *data = (bChildOfConstraint *)cdata; - data->flag = (CHILDOF_LOCX | CHILDOF_LOCY | CHILDOF_LOCZ | - CHILDOF_ROTX | CHILDOF_ROTY | CHILDOF_ROTZ | - CHILDOF_SIZEX | CHILDOF_SIZEY | CHILDOF_SIZEZ); - unit_m4(data->invmat); + data->flag = (CHILDOF_LOCX | CHILDOF_LOCY | CHILDOF_LOCZ | CHILDOF_ROTX | CHILDOF_ROTY | + CHILDOF_ROTZ | CHILDOF_SIZEX | CHILDOF_SIZEY | CHILDOF_SIZEZ); + unit_m4(data->invmat); } static void childof_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bChildOfConstraint *data = con->data; + bChildOfConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int childof_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bChildOfConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bChildOfConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void childof_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bChildOfConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bChildOfConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bChildOfConstraint *data = con->data; - bConstraintTarget *ct = targets->first; - - /* only evaluate if there is a target */ - if (VALID_CONS_TARGET(ct)) { - float parmat[4][4]; - - /* simple matrix parenting */ - if (data->flag == CHILDOF_ALL) { - - /* multiply target (parent matrix) by offset (parent inverse) to get - * the effect of the parent that will be exerted on the owner - */ - mul_m4_m4m4(parmat, ct->matrix, data->invmat); - - /* now multiply the parent matrix by the owner matrix to get the - * the effect of this constraint (i.e. owner is 'parented' to parent) - */ - mul_m4_m4m4(cob->matrix, parmat, cob->matrix); - } - else { - float invmat[4][4], tempmat[4][4]; - float loc[3], eul[3], size[3]; - float loco[3], eulo[3], sizo[3]; - - /* get offset (parent-inverse) matrix */ - copy_m4_m4(invmat, data->invmat); - - /* extract components of both matrices */ - copy_v3_v3(loc, ct->matrix[3]); - mat4_to_eulO(eul, ct->rotOrder, ct->matrix); - mat4_to_size(size, ct->matrix); - - copy_v3_v3(loco, invmat[3]); - mat4_to_eulO(eulo, cob->rotOrder, invmat); - mat4_to_size(sizo, invmat); - - /* disable channels not enabled */ - if (!(data->flag & CHILDOF_LOCX)) loc[0] = loco[0] = 0.0f; - if (!(data->flag & CHILDOF_LOCY)) loc[1] = loco[1] = 0.0f; - if (!(data->flag & CHILDOF_LOCZ)) loc[2] = loco[2] = 0.0f; - if (!(data->flag & CHILDOF_ROTX)) eul[0] = eulo[0] = 0.0f; - if (!(data->flag & CHILDOF_ROTY)) eul[1] = eulo[1] = 0.0f; - if (!(data->flag & CHILDOF_ROTZ)) eul[2] = eulo[2] = 0.0f; - if (!(data->flag & CHILDOF_SIZEX)) size[0] = sizo[0] = 1.0f; - if (!(data->flag & CHILDOF_SIZEY)) size[1] = sizo[1] = 1.0f; - if (!(data->flag & CHILDOF_SIZEZ)) size[2] = sizo[2] = 1.0f; - - /* make new target mat and offset mat */ - loc_eulO_size_to_mat4(ct->matrix, loc, eul, size, ct->rotOrder); - loc_eulO_size_to_mat4(invmat, loco, eulo, sizo, cob->rotOrder); - - /* multiply target (parent matrix) by offset (parent inverse) to get - * the effect of the parent that will be exerted on the owner - */ - mul_m4_m4m4(parmat, ct->matrix, invmat); - - /* now multiply the parent matrix by the owner matrix to get the - * the effect of this constraint (i.e. owner is 'parented' to parent) - */ - copy_m4_m4(tempmat, cob->matrix); - mul_m4_m4m4(cob->matrix, parmat, tempmat); - - /* without this, changes to scale and rotation can change location - * of a parentless bone or a disconnected bone. Even though its set - * to zero above. */ - if (!(data->flag & CHILDOF_LOCX)) cob->matrix[3][0] = tempmat[3][0]; - if (!(data->flag & CHILDOF_LOCY)) cob->matrix[3][1] = tempmat[3][1]; - if (!(data->flag & CHILDOF_LOCZ)) cob->matrix[3][2] = tempmat[3][2]; - } - } + bChildOfConstraint *data = con->data; + bConstraintTarget *ct = targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float parmat[4][4]; + + /* simple matrix parenting */ + if (data->flag == CHILDOF_ALL) { + + /* multiply target (parent matrix) by offset (parent inverse) to get + * the effect of the parent that will be exerted on the owner + */ + mul_m4_m4m4(parmat, ct->matrix, data->invmat); + + /* now multiply the parent matrix by the owner matrix to get the + * the effect of this constraint (i.e. owner is 'parented' to parent) + */ + mul_m4_m4m4(cob->matrix, parmat, cob->matrix); + } + else { + float invmat[4][4], tempmat[4][4]; + float loc[3], eul[3], size[3]; + float loco[3], eulo[3], sizo[3]; + + /* get offset (parent-inverse) matrix */ + copy_m4_m4(invmat, data->invmat); + + /* extract components of both matrices */ + copy_v3_v3(loc, ct->matrix[3]); + mat4_to_eulO(eul, ct->rotOrder, ct->matrix); + mat4_to_size(size, ct->matrix); + + copy_v3_v3(loco, invmat[3]); + mat4_to_eulO(eulo, cob->rotOrder, invmat); + mat4_to_size(sizo, invmat); + + /* disable channels not enabled */ + if (!(data->flag & CHILDOF_LOCX)) + loc[0] = loco[0] = 0.0f; + if (!(data->flag & CHILDOF_LOCY)) + loc[1] = loco[1] = 0.0f; + if (!(data->flag & CHILDOF_LOCZ)) + loc[2] = loco[2] = 0.0f; + if (!(data->flag & CHILDOF_ROTX)) + eul[0] = eulo[0] = 0.0f; + if (!(data->flag & CHILDOF_ROTY)) + eul[1] = eulo[1] = 0.0f; + if (!(data->flag & CHILDOF_ROTZ)) + eul[2] = eulo[2] = 0.0f; + if (!(data->flag & CHILDOF_SIZEX)) + size[0] = sizo[0] = 1.0f; + if (!(data->flag & CHILDOF_SIZEY)) + size[1] = sizo[1] = 1.0f; + if (!(data->flag & CHILDOF_SIZEZ)) + size[2] = sizo[2] = 1.0f; + + /* make new target mat and offset mat */ + loc_eulO_size_to_mat4(ct->matrix, loc, eul, size, ct->rotOrder); + loc_eulO_size_to_mat4(invmat, loco, eulo, sizo, cob->rotOrder); + + /* multiply target (parent matrix) by offset (parent inverse) to get + * the effect of the parent that will be exerted on the owner + */ + mul_m4_m4m4(parmat, ct->matrix, invmat); + + /* now multiply the parent matrix by the owner matrix to get the + * the effect of this constraint (i.e. owner is 'parented' to parent) + */ + copy_m4_m4(tempmat, cob->matrix); + mul_m4_m4m4(cob->matrix, parmat, tempmat); + + /* without this, changes to scale and rotation can change location + * of a parentless bone or a disconnected bone. Even though its set + * to zero above. */ + if (!(data->flag & CHILDOF_LOCX)) + cob->matrix[3][0] = tempmat[3][0]; + if (!(data->flag & CHILDOF_LOCY)) + cob->matrix[3][1] = tempmat[3][1]; + if (!(data->flag & CHILDOF_LOCZ)) + cob->matrix[3][2] = tempmat[3][2]; + } + } } /* XXX note, con->flag should be CONSTRAINT_SPACEONCE for bone-childof, patched in readfile.c */ static bConstraintTypeInfo CTI_CHILDOF = { - CONSTRAINT_TYPE_CHILDOF, /* type */ - sizeof(bChildOfConstraint), /* size */ - "Child Of", /* name */ - "bChildOfConstraint", /* struct name */ - NULL, /* free data */ - childof_id_looper, /* id looper */ - NULL, /* copy data */ - childof_new_data, /* new data */ - childof_get_tars, /* get constraint targets */ - childof_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get a target matrix */ - childof_evaluate, /* evaluate */ + CONSTRAINT_TYPE_CHILDOF, /* type */ + sizeof(bChildOfConstraint), /* size */ + "Child Of", /* name */ + "bChildOfConstraint", /* struct name */ + NULL, /* free data */ + childof_id_looper, /* id looper */ + NULL, /* copy data */ + childof_new_data, /* new data */ + childof_get_tars, /* get constraint targets */ + childof_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get a target matrix */ + childof_evaluate, /* evaluate */ }; /* -------- TrackTo Constraint ------- */ static void trackto_new_data(void *cdata) { - bTrackToConstraint *data = (bTrackToConstraint *)cdata; + bTrackToConstraint *data = (bTrackToConstraint *)cdata; - data->reserved1 = TRACK_Y; - data->reserved2 = UP_Z; + data->reserved1 = TRACK_Y; + data->reserved2 = UP_Z; } static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bTrackToConstraint *data = con->data; + bTrackToConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int trackto_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bTrackToConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bTrackToConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void trackto_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bTrackToConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bTrackToConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } - static int basis_cross(int n, int m) { - switch (n - m) { - case 1: - case -2: - return 1; - - case -1: - case 2: - return -1; - - default: - return 0; - } -} - -static void vectomat(const float vec[3], const float target_up[3], short axis, short upflag, short flags, float m[3][3]) -{ - float n[3]; - float u[3]; /* vector specifying the up axis */ - float proj[3]; - float right[3]; - float neg = -1; - int right_index; - - if (normalize_v3_v3(n, vec) == 0.0f) { - n[0] = 0.0f; - n[1] = 0.0f; - n[2] = 1.0f; - } - if (axis > 2) axis -= 3; - else negate_v3(n); - - /* n specifies the transformation of the track axis */ - if (flags & TARGET_Z_UP) { - /* target Z axis is the global up axis */ - copy_v3_v3(u, target_up); - } - else { - /* world Z axis is the global up axis */ - u[0] = 0; - u[1] = 0; - u[2] = 1; - } - - /* note: even though 'n' is normalized, don't use 'project_v3_v3v3_normalized' below - * because precision issues cause a problem in near degenerate states, see: T53455. */ - - /* project the up vector onto the plane specified by n */ - project_v3_v3v3(proj, u, n); /* first u onto n... */ - sub_v3_v3v3(proj, u, proj); /* then onto the plane */ - /* proj specifies the transformation of the up axis */ - - if (normalize_v3(proj) == 0.0f) { /* degenerate projection */ - proj[0] = 0.0f; - proj[1] = 1.0f; - proj[2] = 0.0f; - } - - /* Normalized cross product of n and proj specifies transformation of the right axis */ - cross_v3_v3v3(right, proj, n); - normalize_v3(right); - - if (axis != upflag) { - right_index = 3 - axis - upflag; - neg = (float)basis_cross(axis, upflag); - - /* account for up direction, track direction */ - m[right_index][0] = neg * right[0]; - m[right_index][1] = neg * right[1]; - m[right_index][2] = neg * right[2]; - - copy_v3_v3(m[upflag], proj); - - copy_v3_v3(m[axis], n); - } - /* identity matrix - don't do anything if the two axes are the same */ - else { - unit_m3(m); - } + switch (n - m) { + case 1: + case -2: + return 1; + + case -1: + case 2: + return -1; + + default: + return 0; + } +} + +static void vectomat(const float vec[3], + const float target_up[3], + short axis, + short upflag, + short flags, + float m[3][3]) +{ + float n[3]; + float u[3]; /* vector specifying the up axis */ + float proj[3]; + float right[3]; + float neg = -1; + int right_index; + + if (normalize_v3_v3(n, vec) == 0.0f) { + n[0] = 0.0f; + n[1] = 0.0f; + n[2] = 1.0f; + } + if (axis > 2) + axis -= 3; + else + negate_v3(n); + + /* n specifies the transformation of the track axis */ + if (flags & TARGET_Z_UP) { + /* target Z axis is the global up axis */ + copy_v3_v3(u, target_up); + } + else { + /* world Z axis is the global up axis */ + u[0] = 0; + u[1] = 0; + u[2] = 1; + } + + /* note: even though 'n' is normalized, don't use 'project_v3_v3v3_normalized' below + * because precision issues cause a problem in near degenerate states, see: T53455. */ + + /* project the up vector onto the plane specified by n */ + project_v3_v3v3(proj, u, n); /* first u onto n... */ + sub_v3_v3v3(proj, u, proj); /* then onto the plane */ + /* proj specifies the transformation of the up axis */ + + if (normalize_v3(proj) == 0.0f) { /* degenerate projection */ + proj[0] = 0.0f; + proj[1] = 1.0f; + proj[2] = 0.0f; + } + + /* Normalized cross product of n and proj specifies transformation of the right axis */ + cross_v3_v3v3(right, proj, n); + normalize_v3(right); + + if (axis != upflag) { + right_index = 3 - axis - upflag; + neg = (float)basis_cross(axis, upflag); + + /* account for up direction, track direction */ + m[right_index][0] = neg * right[0]; + m[right_index][1] = neg * right[1]; + m[right_index][2] = neg * right[2]; + + copy_v3_v3(m[upflag], proj); + + copy_v3_v3(m[axis], n); + } + /* identity matrix - don't do anything if the two axes are the same */ + else { + unit_m3(m); + } } - static void trackto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bTrackToConstraint *data = con->data; - bConstraintTarget *ct = targets->first; + bTrackToConstraint *data = con->data; + bConstraintTarget *ct = targets->first; - if (VALID_CONS_TARGET(ct)) { - float size[3], vec[3]; - float totmat[3][3]; + if (VALID_CONS_TARGET(ct)) { + float size[3], vec[3]; + float totmat[3][3]; - /* Get size property, since ob->scale is only the object's own relative size, not its global one */ - mat4_to_size(size, cob->matrix); + /* Get size property, since ob->scale is only the object's own relative size, not its global one */ + mat4_to_size(size, cob->matrix); - /* Clear the object's rotation */ - cob->matrix[0][0] = size[0]; - cob->matrix[0][1] = 0; - cob->matrix[0][2] = 0; - cob->matrix[1][0] = 0; - cob->matrix[1][1] = size[1]; - cob->matrix[1][2] = 0; - cob->matrix[2][0] = 0; - cob->matrix[2][1] = 0; - cob->matrix[2][2] = size[2]; + /* Clear the object's rotation */ + cob->matrix[0][0] = size[0]; + cob->matrix[0][1] = 0; + cob->matrix[0][2] = 0; + cob->matrix[1][0] = 0; + cob->matrix[1][1] = size[1]; + cob->matrix[1][2] = 0; + cob->matrix[2][0] = 0; + cob->matrix[2][1] = 0; + cob->matrix[2][2] = size[2]; - /* targetmat[2] instead of ownermat[2] is passed to vectomat - * for backwards compatibility it seems... (Aligorith) - */ - sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]); - vectomat(vec, ct->matrix[2], - (short)data->reserved1, (short)data->reserved2, - data->flags, totmat); + /* targetmat[2] instead of ownermat[2] is passed to vectomat + * for backwards compatibility it seems... (Aligorith) + */ + sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]); + vectomat( + vec, ct->matrix[2], (short)data->reserved1, (short)data->reserved2, data->flags, totmat); - mul_m4_m3m4(cob->matrix, totmat, cob->matrix); - } + mul_m4_m3m4(cob->matrix, totmat, cob->matrix); + } } static bConstraintTypeInfo CTI_TRACKTO = { - CONSTRAINT_TYPE_TRACKTO, /* type */ - sizeof(bTrackToConstraint), /* size */ - "Track To", /* name */ - "bTrackToConstraint", /* struct name */ - NULL, /* free data */ - trackto_id_looper, /* id looper */ - NULL, /* copy data */ - trackto_new_data, /* new data */ - trackto_get_tars, /* get constraint targets */ - trackto_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ - trackto_evaluate, /* evaluate */ + CONSTRAINT_TYPE_TRACKTO, /* type */ + sizeof(bTrackToConstraint), /* size */ + "Track To", /* name */ + "bTrackToConstraint", /* struct name */ + NULL, /* free data */ + trackto_id_looper, /* id looper */ + NULL, /* copy data */ + trackto_new_data, /* new data */ + trackto_get_tars, /* get constraint targets */ + trackto_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + trackto_evaluate, /* evaluate */ }; /* --------- Inverse-Kinematics --------- */ static void kinematic_new_data(void *cdata) { - bKinematicConstraint *data = (bKinematicConstraint *)cdata; + bKinematicConstraint *data = (bKinematicConstraint *)cdata; - data->weight = 1.0f; - data->orientweight = 1.0f; - data->iterations = 500; - data->dist = 1.0f; - data->flag = CONSTRAINT_IK_TIP | CONSTRAINT_IK_STRETCH | CONSTRAINT_IK_POS; + data->weight = 1.0f; + data->orientweight = 1.0f; + data->iterations = 500; + data->dist = 1.0f; + data->flag = CONSTRAINT_IK_TIP | CONSTRAINT_IK_STRETCH | CONSTRAINT_IK_POS; } static void kinematic_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bKinematicConstraint *data = con->data; + bKinematicConstraint *data = con->data; - /* chain target */ - func(con, (ID **)&data->tar, false, userdata); + /* chain target */ + func(con, (ID **)&data->tar, false, userdata); - /* poletarget */ - func(con, (ID **)&data->poletar, false, userdata); + /* poletarget */ + func(con, (ID **)&data->poletar, false, userdata); } static int kinematic_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bKinematicConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bKinematicConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints is used twice here */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - SINGLETARGET_GET_TARS(con, data->poletar, data->polesubtarget, ct, list); + /* standard target-getting macro for single-target constraints is used twice here */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + SINGLETARGET_GET_TARS(con, data->poletar, data->polesubtarget, ct, list); - return 2; - } + return 2; + } - return 0; + return 0; } static void kinematic_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bKinematicConstraint *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, no_copy); - SINGLETARGET_FLUSH_TARS(con, data->poletar, data->polesubtarget, ct, list, no_copy); - } -} - -static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) -{ - bKinematicConstraint *data = con->data; - - if (VALID_CONS_TARGET(ct)) - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail); - else if (ct) { - if (data->flag & CONSTRAINT_IK_AUTO) { - Object *ob = cob->ob; - - if (ob == NULL) { - unit_m4(ct->matrix); - } - else { - float vec[3]; - /* move grabtarget into world space */ - mul_v3_m4v3(vec, ob->obmat, data->grabtarget); - copy_m4_m4(ct->matrix, ob->obmat); - copy_v3_v3(ct->matrix[3], vec); - } - } - else - unit_m4(ct->matrix); - } + if (con && list) { + bKinematicConstraint *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, no_copy); + SINGLETARGET_FLUSH_TARS(con, data->poletar, data->polesubtarget, ct, list, no_copy); + } +} + +static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), + bConstraint *con, + bConstraintOb *cob, + bConstraintTarget *ct, + float UNUSED(ctime)) +{ + bKinematicConstraint *data = con->data; + + if (VALID_CONS_TARGET(ct)) + constraint_target_to_mat4(ct->tar, + ct->subtarget, + ct->matrix, + CONSTRAINT_SPACE_WORLD, + ct->space, + con->flag, + con->headtail); + else if (ct) { + if (data->flag & CONSTRAINT_IK_AUTO) { + Object *ob = cob->ob; + + if (ob == NULL) { + unit_m4(ct->matrix); + } + else { + float vec[3]; + /* move grabtarget into world space */ + mul_v3_m4v3(vec, ob->obmat, data->grabtarget); + copy_m4_m4(ct->matrix, ob->obmat); + copy_v3_v3(ct->matrix[3], vec); + } + } + else + unit_m4(ct->matrix); + } } static bConstraintTypeInfo CTI_KINEMATIC = { - CONSTRAINT_TYPE_KINEMATIC, /* type */ - sizeof(bKinematicConstraint), /* size */ - "IK", /* name */ - "bKinematicConstraint", /* struct name */ - NULL, /* free data */ - kinematic_id_looper, /* id looper */ - NULL, /* copy data */ - kinematic_new_data, /* new data */ - kinematic_get_tars, /* get constraint targets */ - kinematic_flush_tars, /* flush constraint targets */ - kinematic_get_tarmat, /* get target matrix */ - NULL, /* evaluate - solved as separate loop */ + CONSTRAINT_TYPE_KINEMATIC, /* type */ + sizeof(bKinematicConstraint), /* size */ + "IK", /* name */ + "bKinematicConstraint", /* struct name */ + NULL, /* free data */ + kinematic_id_looper, /* id looper */ + NULL, /* copy data */ + kinematic_new_data, /* new data */ + kinematic_get_tars, /* get constraint targets */ + kinematic_flush_tars, /* flush constraint targets */ + kinematic_get_tarmat, /* get target matrix */ + NULL, /* evaluate - solved as separate loop */ }; /* -------- Follow-Path Constraint ---------- */ static void followpath_new_data(void *cdata) { - bFollowPathConstraint *data = (bFollowPathConstraint *)cdata; + bFollowPathConstraint *data = (bFollowPathConstraint *)cdata; - data->trackflag = TRACK_Y; - data->upflag = UP_Z; - data->offset = 0; - data->followflag = 0; + data->trackflag = TRACK_Y; + data->upflag = UP_Z; + data->offset = 0; + data->followflag = 0; } static void followpath_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bFollowPathConstraint *data = con->data; + bFollowPathConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int followpath_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bFollowPathConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bFollowPathConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints without subtargets */ - SINGLETARGETNS_GET_TARS(con, data->tar, ct, list); + /* standard target-getting macro for single-target constraints without subtargets */ + SINGLETARGETNS_GET_TARS(con, data->tar, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void followpath_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bFollowPathConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bFollowPathConstraint *data = con->data; + bConstraintTarget *ct = list->first; - /* the following macro is used for all standard single-target constraints */ - SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy); + } } static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph), - bConstraint *con, bConstraintOb *UNUSED(cob), - bConstraintTarget *ct, float UNUSED(ctime)) -{ - bFollowPathConstraint *data = con->data; - - if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) { - Curve *cu = ct->tar->data; - float vec[4], dir[3], radius; - float curvetime; - - unit_m4(ct->matrix); - - /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, - * currently for paths to work it needs to go through the bevlist/displist system (ton) - */ - - if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->path && ct->tar->runtime.curve_cache->path->data) { - float quat[4]; - if ((data->followflag & FOLLOWPATH_STATIC) == 0) { - /* animated position along curve depending on time */ - Nurb *nu = cu->nurb.first; - curvetime = cu->ctime - data->offset; - - /* ctime is now a proper var setting of Curve which gets set by Animato like any other var that's animated, - * but this will only work if it actually is animated... - * - * we divide the curvetime calculated in the previous step by the length of the path, to get a time - * factor, which then gets clamped to lie within 0.0 - 1.0 range - */ - curvetime /= cu->pathlen; - - if (nu && nu->flagu & CU_NURB_CYCLIC) { - /* If the curve is cyclic, enable looping around if the time is - * outside the bounds 0..1 */ - if ((curvetime < 0.0f) || (curvetime > 1.0f)) { - curvetime -= floorf(curvetime); - } - } - else { - /* The curve is not cyclic, so clamp to the begin/end points. */ - CLAMP(curvetime, 0.0f, 1.0f); - } - } - else { - /* fixed position along curve */ - curvetime = data->offset_fac; - } - - if (where_on_path(ct->tar, curvetime, vec, dir, (data->followflag & FOLLOWPATH_FOLLOW) ? quat : NULL, &radius, NULL) ) { /* quat_pt is quat or NULL*/ - float totmat[4][4]; - unit_m4(totmat); - - if (data->followflag & FOLLOWPATH_FOLLOW) { - quat_apply_track(quat, data->trackflag, data->upflag); - quat_to_mat4(totmat, quat); - } - - if (data->followflag & FOLLOWPATH_RADIUS) { - float tmat[4][4], rmat[4][4]; - scale_m4_fl(tmat, radius); - mul_m4_m4m4(rmat, tmat, totmat); - copy_m4_m4(totmat, rmat); - } - - copy_v3_v3(totmat[3], vec); - - mul_m4_m4m4(ct->matrix, ct->tar->obmat, totmat); - } - } - } - else if (ct) - unit_m4(ct->matrix); + bConstraint *con, + bConstraintOb *UNUSED(cob), + bConstraintTarget *ct, + float UNUSED(ctime)) +{ + bFollowPathConstraint *data = con->data; + + if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) { + Curve *cu = ct->tar->data; + float vec[4], dir[3], radius; + float curvetime; + + unit_m4(ct->matrix); + + /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, + * currently for paths to work it needs to go through the bevlist/displist system (ton) + */ + + if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->path && + ct->tar->runtime.curve_cache->path->data) { + float quat[4]; + if ((data->followflag & FOLLOWPATH_STATIC) == 0) { + /* animated position along curve depending on time */ + Nurb *nu = cu->nurb.first; + curvetime = cu->ctime - data->offset; + + /* ctime is now a proper var setting of Curve which gets set by Animato like any other var that's animated, + * but this will only work if it actually is animated... + * + * we divide the curvetime calculated in the previous step by the length of the path, to get a time + * factor, which then gets clamped to lie within 0.0 - 1.0 range + */ + curvetime /= cu->pathlen; + + if (nu && nu->flagu & CU_NURB_CYCLIC) { + /* If the curve is cyclic, enable looping around if the time is + * outside the bounds 0..1 */ + if ((curvetime < 0.0f) || (curvetime > 1.0f)) { + curvetime -= floorf(curvetime); + } + } + else { + /* The curve is not cyclic, so clamp to the begin/end points. */ + CLAMP(curvetime, 0.0f, 1.0f); + } + } + else { + /* fixed position along curve */ + curvetime = data->offset_fac; + } + + if (where_on_path(ct->tar, + curvetime, + vec, + dir, + (data->followflag & FOLLOWPATH_FOLLOW) ? quat : NULL, + &radius, + NULL)) { /* quat_pt is quat or NULL*/ + float totmat[4][4]; + unit_m4(totmat); + + if (data->followflag & FOLLOWPATH_FOLLOW) { + quat_apply_track(quat, data->trackflag, data->upflag); + quat_to_mat4(totmat, quat); + } + + if (data->followflag & FOLLOWPATH_RADIUS) { + float tmat[4][4], rmat[4][4]; + scale_m4_fl(tmat, radius); + mul_m4_m4m4(rmat, tmat, totmat); + copy_m4_m4(totmat, rmat); + } + + copy_v3_v3(totmat[3], vec); + + mul_m4_m4m4(ct->matrix, ct->tar->obmat, totmat); + } + } + } + else if (ct) + unit_m4(ct->matrix); } static void followpath_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bConstraintTarget *ct = targets->first; + bConstraintTarget *ct = targets->first; - /* only evaluate if there is a target */ - if (VALID_CONS_TARGET(ct)) { - float obmat[4][4]; - float size[3]; - bFollowPathConstraint *data = con->data; + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float obmat[4][4]; + float size[3]; + bFollowPathConstraint *data = con->data; - /* get Object transform (loc/rot/size) to determine transformation from path */ - /* TODO: this used to be local at one point, but is probably more useful as-is */ - copy_m4_m4(obmat, cob->matrix); + /* get Object transform (loc/rot/size) to determine transformation from path */ + /* TODO: this used to be local at one point, but is probably more useful as-is */ + copy_m4_m4(obmat, cob->matrix); - /* get scaling of object before applying constraint */ - mat4_to_size(size, cob->matrix); + /* get scaling of object before applying constraint */ + mat4_to_size(size, cob->matrix); - /* apply targetmat - containing location on path, and rotation */ - mul_m4_m4m4(cob->matrix, ct->matrix, obmat); + /* apply targetmat - containing location on path, and rotation */ + mul_m4_m4m4(cob->matrix, ct->matrix, obmat); - /* un-apply scaling caused by path */ - if ((data->followflag & FOLLOWPATH_RADIUS) == 0) { /* XXX - assume that scale correction means that radius will have some scale error in it - Campbell */ - float obsize[3]; + /* un-apply scaling caused by path */ + if ((data->followflag & FOLLOWPATH_RADIUS) == + 0) { /* XXX - assume that scale correction means that radius will have some scale error in it - Campbell */ + float obsize[3]; - mat4_to_size(obsize, cob->matrix); - if (obsize[0]) - mul_v3_fl(cob->matrix[0], size[0] / obsize[0]); - if (obsize[1]) - mul_v3_fl(cob->matrix[1], size[1] / obsize[1]); - if (obsize[2]) - mul_v3_fl(cob->matrix[2], size[2] / obsize[2]); - } - } + mat4_to_size(obsize, cob->matrix); + if (obsize[0]) + mul_v3_fl(cob->matrix[0], size[0] / obsize[0]); + if (obsize[1]) + mul_v3_fl(cob->matrix[1], size[1] / obsize[1]); + if (obsize[2]) + mul_v3_fl(cob->matrix[2], size[2] / obsize[2]); + } + } } static bConstraintTypeInfo CTI_FOLLOWPATH = { - CONSTRAINT_TYPE_FOLLOWPATH, /* type */ - sizeof(bFollowPathConstraint), /* size */ - "Follow Path", /* name */ - "bFollowPathConstraint", /* struct name */ - NULL, /* free data */ - followpath_id_looper, /* id looper */ - NULL, /* copy data */ - followpath_new_data, /* new data */ - followpath_get_tars, /* get constraint targets */ - followpath_flush_tars, /* flush constraint targets */ - followpath_get_tarmat, /* get target matrix */ - followpath_evaluate, /* evaluate */ + CONSTRAINT_TYPE_FOLLOWPATH, /* type */ + sizeof(bFollowPathConstraint), /* size */ + "Follow Path", /* name */ + "bFollowPathConstraint", /* struct name */ + NULL, /* free data */ + followpath_id_looper, /* id looper */ + NULL, /* copy data */ + followpath_new_data, /* new data */ + followpath_get_tars, /* get constraint targets */ + followpath_flush_tars, /* flush constraint targets */ + followpath_get_tarmat, /* get target matrix */ + followpath_evaluate, /* evaluate */ }; /* --------- Limit Location --------- */ - static void loclimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) { - bLocLimitConstraint *data = con->data; - - if (data->flag & LIMIT_XMIN) { - if (cob->matrix[3][0] < data->xmin) - cob->matrix[3][0] = data->xmin; - } - if (data->flag & LIMIT_XMAX) { - if (cob->matrix[3][0] > data->xmax) - cob->matrix[3][0] = data->xmax; - } - if (data->flag & LIMIT_YMIN) { - if (cob->matrix[3][1] < data->ymin) - cob->matrix[3][1] = data->ymin; - } - if (data->flag & LIMIT_YMAX) { - if (cob->matrix[3][1] > data->ymax) - cob->matrix[3][1] = data->ymax; - } - if (data->flag & LIMIT_ZMIN) { - if (cob->matrix[3][2] < data->zmin) - cob->matrix[3][2] = data->zmin; - } - if (data->flag & LIMIT_ZMAX) { - if (cob->matrix[3][2] > data->zmax) - cob->matrix[3][2] = data->zmax; - } + bLocLimitConstraint *data = con->data; + + if (data->flag & LIMIT_XMIN) { + if (cob->matrix[3][0] < data->xmin) + cob->matrix[3][0] = data->xmin; + } + if (data->flag & LIMIT_XMAX) { + if (cob->matrix[3][0] > data->xmax) + cob->matrix[3][0] = data->xmax; + } + if (data->flag & LIMIT_YMIN) { + if (cob->matrix[3][1] < data->ymin) + cob->matrix[3][1] = data->ymin; + } + if (data->flag & LIMIT_YMAX) { + if (cob->matrix[3][1] > data->ymax) + cob->matrix[3][1] = data->ymax; + } + if (data->flag & LIMIT_ZMIN) { + if (cob->matrix[3][2] < data->zmin) + cob->matrix[3][2] = data->zmin; + } + if (data->flag & LIMIT_ZMAX) { + if (cob->matrix[3][2] > data->zmax) + cob->matrix[3][2] = data->zmax; + } } static bConstraintTypeInfo CTI_LOCLIMIT = { - CONSTRAINT_TYPE_LOCLIMIT, /* type */ - sizeof(bLocLimitConstraint), /* size */ - "Limit Location", /* name */ - "bLocLimitConstraint", /* struct name */ - NULL, /* free data */ - NULL, /* id looper */ - NULL, /* copy data */ - NULL, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ - NULL, /* get target matrix */ - loclimit_evaluate, /* evaluate */ + CONSTRAINT_TYPE_LOCLIMIT, /* type */ + sizeof(bLocLimitConstraint), /* size */ + "Limit Location", /* name */ + "bLocLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* id looper */ + NULL, /* copy data */ + NULL, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + loclimit_evaluate, /* evaluate */ }; /* -------- Limit Rotation --------- */ static void rotlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) { - bRotLimitConstraint *data = con->data; - float loc[3]; - float eul[3]; - float size[3]; + bRotLimitConstraint *data = con->data; + float loc[3]; + float eul[3]; + float size[3]; - copy_v3_v3(loc, cob->matrix[3]); - mat4_to_size(size, cob->matrix); + copy_v3_v3(loc, cob->matrix[3]); + mat4_to_size(size, cob->matrix); - mat4_to_eulO(eul, cob->rotOrder, cob->matrix); + mat4_to_eulO(eul, cob->rotOrder, cob->matrix); - /* constraint data uses radians internally */ + /* constraint data uses radians internally */ - /* limiting of euler values... */ - if (data->flag & LIMIT_XROT) { - if (eul[0] < data->xmin) - eul[0] = data->xmin; + /* limiting of euler values... */ + if (data->flag & LIMIT_XROT) { + if (eul[0] < data->xmin) + eul[0] = data->xmin; - if (eul[0] > data->xmax) - eul[0] = data->xmax; - } - if (data->flag & LIMIT_YROT) { - if (eul[1] < data->ymin) - eul[1] = data->ymin; + if (eul[0] > data->xmax) + eul[0] = data->xmax; + } + if (data->flag & LIMIT_YROT) { + if (eul[1] < data->ymin) + eul[1] = data->ymin; - if (eul[1] > data->ymax) - eul[1] = data->ymax; - } - if (data->flag & LIMIT_ZROT) { - if (eul[2] < data->zmin) - eul[2] = data->zmin; + if (eul[1] > data->ymax) + eul[1] = data->ymax; + } + if (data->flag & LIMIT_ZROT) { + if (eul[2] < data->zmin) + eul[2] = data->zmin; - if (eul[2] > data->zmax) - eul[2] = data->zmax; - } + if (eul[2] > data->zmax) + eul[2] = data->zmax; + } - loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder); + loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder); } static bConstraintTypeInfo CTI_ROTLIMIT = { - CONSTRAINT_TYPE_ROTLIMIT, /* type */ - sizeof(bRotLimitConstraint), /* size */ - "Limit Rotation", /* name */ - "bRotLimitConstraint", /* struct name */ - NULL, /* free data */ - NULL, /* id looper */ - NULL, /* copy data */ - NULL, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ - NULL, /* get target matrix */ - rotlimit_evaluate, /* evaluate */ + CONSTRAINT_TYPE_ROTLIMIT, /* type */ + sizeof(bRotLimitConstraint), /* size */ + "Limit Rotation", /* name */ + "bRotLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* id looper */ + NULL, /* copy data */ + NULL, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + rotlimit_evaluate, /* evaluate */ }; /* --------- Limit Scale --------- */ - static void sizelimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) { - bSizeLimitConstraint *data = con->data; - float obsize[3], size[3]; - - mat4_to_size(size, cob->matrix); - mat4_to_size(obsize, cob->matrix); - - if (data->flag & LIMIT_XMIN) { - if (size[0] < data->xmin) - size[0] = data->xmin; - } - if (data->flag & LIMIT_XMAX) { - if (size[0] > data->xmax) - size[0] = data->xmax; - } - if (data->flag & LIMIT_YMIN) { - if (size[1] < data->ymin) - size[1] = data->ymin; - } - if (data->flag & LIMIT_YMAX) { - if (size[1] > data->ymax) - size[1] = data->ymax; - } - if (data->flag & LIMIT_ZMIN) { - if (size[2] < data->zmin) - size[2] = data->zmin; - } - if (data->flag & LIMIT_ZMAX) { - if (size[2] > data->zmax) - size[2] = data->zmax; - } - - if (obsize[0]) - mul_v3_fl(cob->matrix[0], size[0] / obsize[0]); - if (obsize[1]) - mul_v3_fl(cob->matrix[1], size[1] / obsize[1]); - if (obsize[2]) - mul_v3_fl(cob->matrix[2], size[2] / obsize[2]); + bSizeLimitConstraint *data = con->data; + float obsize[3], size[3]; + + mat4_to_size(size, cob->matrix); + mat4_to_size(obsize, cob->matrix); + + if (data->flag & LIMIT_XMIN) { + if (size[0] < data->xmin) + size[0] = data->xmin; + } + if (data->flag & LIMIT_XMAX) { + if (size[0] > data->xmax) + size[0] = data->xmax; + } + if (data->flag & LIMIT_YMIN) { + if (size[1] < data->ymin) + size[1] = data->ymin; + } + if (data->flag & LIMIT_YMAX) { + if (size[1] > data->ymax) + size[1] = data->ymax; + } + if (data->flag & LIMIT_ZMIN) { + if (size[2] < data->zmin) + size[2] = data->zmin; + } + if (data->flag & LIMIT_ZMAX) { + if (size[2] > data->zmax) + size[2] = data->zmax; + } + + if (obsize[0]) + mul_v3_fl(cob->matrix[0], size[0] / obsize[0]); + if (obsize[1]) + mul_v3_fl(cob->matrix[1], size[1] / obsize[1]); + if (obsize[2]) + mul_v3_fl(cob->matrix[2], size[2] / obsize[2]); } static bConstraintTypeInfo CTI_SIZELIMIT = { - CONSTRAINT_TYPE_SIZELIMIT, /* type */ - sizeof(bSizeLimitConstraint), /* size */ - "Limit Scale", /* name */ - "bSizeLimitConstraint", /* struct name */ - NULL, /* free data */ - NULL, /* id looper */ - NULL, /* copy data */ - NULL, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ - NULL, /* get target matrix */ - sizelimit_evaluate, /* evaluate */ + CONSTRAINT_TYPE_SIZELIMIT, /* type */ + sizeof(bSizeLimitConstraint), /* size */ + "Limit Scale", /* name */ + "bSizeLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* id looper */ + NULL, /* copy data */ + NULL, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + sizelimit_evaluate, /* evaluate */ }; /* ----------- Copy Location ------------- */ static void loclike_new_data(void *cdata) { - bLocateLikeConstraint *data = (bLocateLikeConstraint *)cdata; + bLocateLikeConstraint *data = (bLocateLikeConstraint *)cdata; - data->flag = LOCLIKE_X | LOCLIKE_Y | LOCLIKE_Z; + data->flag = LOCLIKE_X | LOCLIKE_Y | LOCLIKE_Z; } static void loclike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bLocateLikeConstraint *data = con->data; + bLocateLikeConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int loclike_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bLocateLikeConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bLocateLikeConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void loclike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bLocateLikeConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bLocateLikeConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } static void loclike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bLocateLikeConstraint *data = con->data; - bConstraintTarget *ct = targets->first; + bLocateLikeConstraint *data = con->data; + bConstraintTarget *ct = targets->first; - if (VALID_CONS_TARGET(ct)) { - float offset[3] = {0.0f, 0.0f, 0.0f}; + if (VALID_CONS_TARGET(ct)) { + float offset[3] = {0.0f, 0.0f, 0.0f}; - if (data->flag & LOCLIKE_OFFSET) - copy_v3_v3(offset, cob->matrix[3]); + if (data->flag & LOCLIKE_OFFSET) + copy_v3_v3(offset, cob->matrix[3]); - if (data->flag & LOCLIKE_X) { - cob->matrix[3][0] = ct->matrix[3][0]; + if (data->flag & LOCLIKE_X) { + cob->matrix[3][0] = ct->matrix[3][0]; - if (data->flag & LOCLIKE_X_INVERT) cob->matrix[3][0] *= -1; - cob->matrix[3][0] += offset[0]; - } - if (data->flag & LOCLIKE_Y) { - cob->matrix[3][1] = ct->matrix[3][1]; + if (data->flag & LOCLIKE_X_INVERT) + cob->matrix[3][0] *= -1; + cob->matrix[3][0] += offset[0]; + } + if (data->flag & LOCLIKE_Y) { + cob->matrix[3][1] = ct->matrix[3][1]; - if (data->flag & LOCLIKE_Y_INVERT) cob->matrix[3][1] *= -1; - cob->matrix[3][1] += offset[1]; - } - if (data->flag & LOCLIKE_Z) { - cob->matrix[3][2] = ct->matrix[3][2]; + if (data->flag & LOCLIKE_Y_INVERT) + cob->matrix[3][1] *= -1; + cob->matrix[3][1] += offset[1]; + } + if (data->flag & LOCLIKE_Z) { + cob->matrix[3][2] = ct->matrix[3][2]; - if (data->flag & LOCLIKE_Z_INVERT) cob->matrix[3][2] *= -1; - cob->matrix[3][2] += offset[2]; - } - } + if (data->flag & LOCLIKE_Z_INVERT) + cob->matrix[3][2] *= -1; + cob->matrix[3][2] += offset[2]; + } + } } static bConstraintTypeInfo CTI_LOCLIKE = { - CONSTRAINT_TYPE_LOCLIKE, /* type */ - sizeof(bLocateLikeConstraint), /* size */ - "Copy Location", /* name */ - "bLocateLikeConstraint", /* struct name */ - NULL, /* free data */ - loclike_id_looper, /* id looper */ - NULL, /* copy data */ - loclike_new_data, /* new data */ - loclike_get_tars, /* get constraint targets */ - loclike_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ - loclike_evaluate, /* evaluate */ + CONSTRAINT_TYPE_LOCLIKE, /* type */ + sizeof(bLocateLikeConstraint), /* size */ + "Copy Location", /* name */ + "bLocateLikeConstraint", /* struct name */ + NULL, /* free data */ + loclike_id_looper, /* id looper */ + NULL, /* copy data */ + loclike_new_data, /* new data */ + loclike_get_tars, /* get constraint targets */ + loclike_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + loclike_evaluate, /* evaluate */ }; /* ----------- Copy Rotation ------------- */ static void rotlike_new_data(void *cdata) { - bRotateLikeConstraint *data = (bRotateLikeConstraint *)cdata; + bRotateLikeConstraint *data = (bRotateLikeConstraint *)cdata; - data->flag = ROTLIKE_X | ROTLIKE_Y | ROTLIKE_Z; + data->flag = ROTLIKE_X | ROTLIKE_Y | ROTLIKE_Z; } static void rotlike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bRotateLikeConstraint *data = con->data; + bRotateLikeConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int rotlike_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bRotateLikeConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bRotateLikeConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void rotlike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bRotateLikeConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bRotateLikeConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bRotateLikeConstraint *data = con->data; - bConstraintTarget *ct = targets->first; + bRotateLikeConstraint *data = con->data; + bConstraintTarget *ct = targets->first; - if (VALID_CONS_TARGET(ct)) { - float loc[3]; - float eul[3], obeul[3]; - float size[3]; + if (VALID_CONS_TARGET(ct)) { + float loc[3]; + float eul[3], obeul[3]; + float size[3]; - copy_v3_v3(loc, cob->matrix[3]); - mat4_to_size(size, cob->matrix); + copy_v3_v3(loc, cob->matrix[3]); + mat4_to_size(size, cob->matrix); - /* to allow compatible rotations, must get both rotations in the order of the owner... */ - mat4_to_eulO(obeul, cob->rotOrder, cob->matrix); - /* we must get compatible eulers from the beginning because some of them can be modified below (see bug #21875) */ - mat4_to_compatible_eulO(eul, obeul, cob->rotOrder, ct->matrix); + /* to allow compatible rotations, must get both rotations in the order of the owner... */ + mat4_to_eulO(obeul, cob->rotOrder, cob->matrix); + /* we must get compatible eulers from the beginning because some of them can be modified below (see bug #21875) */ + mat4_to_compatible_eulO(eul, obeul, cob->rotOrder, ct->matrix); - if ((data->flag & ROTLIKE_X) == 0) - eul[0] = obeul[0]; - else { - if (data->flag & ROTLIKE_OFFSET) - rotate_eulO(eul, cob->rotOrder, 'X', obeul[0]); + if ((data->flag & ROTLIKE_X) == 0) + eul[0] = obeul[0]; + else { + if (data->flag & ROTLIKE_OFFSET) + rotate_eulO(eul, cob->rotOrder, 'X', obeul[0]); - if (data->flag & ROTLIKE_X_INVERT) - eul[0] *= -1; - } + if (data->flag & ROTLIKE_X_INVERT) + eul[0] *= -1; + } - if ((data->flag & ROTLIKE_Y) == 0) - eul[1] = obeul[1]; - else { - if (data->flag & ROTLIKE_OFFSET) - rotate_eulO(eul, cob->rotOrder, 'Y', obeul[1]); + if ((data->flag & ROTLIKE_Y) == 0) + eul[1] = obeul[1]; + else { + if (data->flag & ROTLIKE_OFFSET) + rotate_eulO(eul, cob->rotOrder, 'Y', obeul[1]); - if (data->flag & ROTLIKE_Y_INVERT) - eul[1] *= -1; - } + if (data->flag & ROTLIKE_Y_INVERT) + eul[1] *= -1; + } - if ((data->flag & ROTLIKE_Z) == 0) - eul[2] = obeul[2]; - else { - if (data->flag & ROTLIKE_OFFSET) - rotate_eulO(eul, cob->rotOrder, 'Z', obeul[2]); + if ((data->flag & ROTLIKE_Z) == 0) + eul[2] = obeul[2]; + else { + if (data->flag & ROTLIKE_OFFSET) + rotate_eulO(eul, cob->rotOrder, 'Z', obeul[2]); - if (data->flag & ROTLIKE_Z_INVERT) - eul[2] *= -1; - } + if (data->flag & ROTLIKE_Z_INVERT) + eul[2] *= -1; + } - /* 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, cob->rotOrder); - } + /* 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, cob->rotOrder); + } } static bConstraintTypeInfo CTI_ROTLIKE = { - CONSTRAINT_TYPE_ROTLIKE, /* type */ - sizeof(bRotateLikeConstraint), /* size */ - "Copy Rotation", /* name */ - "bRotateLikeConstraint", /* struct name */ - NULL, /* free data */ - rotlike_id_looper, /* id looper */ - NULL, /* copy data */ - rotlike_new_data, /* new data */ - rotlike_get_tars, /* get constraint targets */ - rotlike_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ - rotlike_evaluate, /* evaluate */ + CONSTRAINT_TYPE_ROTLIKE, /* type */ + sizeof(bRotateLikeConstraint), /* size */ + "Copy Rotation", /* name */ + "bRotateLikeConstraint", /* struct name */ + NULL, /* free data */ + rotlike_id_looper, /* id looper */ + NULL, /* copy data */ + rotlike_new_data, /* new data */ + rotlike_get_tars, /* get constraint targets */ + rotlike_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + rotlike_evaluate, /* evaluate */ }; /* ---------- Copy Scale ---------- */ static void sizelike_new_data(void *cdata) { - bSizeLikeConstraint *data = (bSizeLikeConstraint *)cdata; + bSizeLikeConstraint *data = (bSizeLikeConstraint *)cdata; - data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z | SIZELIKE_MULTIPLY; + data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z | SIZELIKE_MULTIPLY; } static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bSizeLikeConstraint *data = con->data; + bSizeLikeConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int sizelike_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bSizeLikeConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bSizeLikeConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void sizelike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bSizeLikeConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bSizeLikeConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bSizeLikeConstraint *data = con->data; - bConstraintTarget *ct = targets->first; - - if (VALID_CONS_TARGET(ct)) { - float obsize[3], size[3]; - - mat4_to_size(size, ct->matrix); - mat4_to_size(obsize, cob->matrix); - - if (data->flag & SIZELIKE_OFFSET) { - /* Scale is a multiplicative quantity, so adding it makes no sense. - * However, the additive mode has to stay for backward compatibility. */ - if (data->flag & SIZELIKE_MULTIPLY) { - /* size[i] *= obsize[i] */ - mul_v3_v3(size, obsize); - } - else { - /* 2.7 compatibility mode: size[i] += (obsize[i] - 1.0f) */ - add_v3_v3(size, obsize); - add_v3_fl(size, -1.0f); - } - } - - if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) { - mul_v3_fl(cob->matrix[0], size[0] / obsize[0]); - } - if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) { - mul_v3_fl(cob->matrix[1], size[1] / obsize[1]); - } - if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) { - mul_v3_fl(cob->matrix[2], size[2] / obsize[2]); - } - } + bSizeLikeConstraint *data = con->data; + bConstraintTarget *ct = targets->first; + + if (VALID_CONS_TARGET(ct)) { + float obsize[3], size[3]; + + mat4_to_size(size, ct->matrix); + mat4_to_size(obsize, cob->matrix); + + if (data->flag & SIZELIKE_OFFSET) { + /* Scale is a multiplicative quantity, so adding it makes no sense. + * However, the additive mode has to stay for backward compatibility. */ + if (data->flag & SIZELIKE_MULTIPLY) { + /* size[i] *= obsize[i] */ + mul_v3_v3(size, obsize); + } + else { + /* 2.7 compatibility mode: size[i] += (obsize[i] - 1.0f) */ + add_v3_v3(size, obsize); + add_v3_fl(size, -1.0f); + } + } + + if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) { + mul_v3_fl(cob->matrix[0], size[0] / obsize[0]); + } + if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) { + mul_v3_fl(cob->matrix[1], size[1] / obsize[1]); + } + if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) { + mul_v3_fl(cob->matrix[2], size[2] / obsize[2]); + } + } } static bConstraintTypeInfo CTI_SIZELIKE = { - CONSTRAINT_TYPE_SIZELIKE, /* type */ - sizeof(bSizeLikeConstraint), /* size */ - "Copy Scale", /* name */ - "bSizeLikeConstraint", /* struct name */ - NULL, /* free data */ - sizelike_id_looper, /* id looper */ - NULL, /* copy data */ - sizelike_new_data, /* new data */ - sizelike_get_tars, /* get constraint targets */ - sizelike_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ - sizelike_evaluate, /* evaluate */ + CONSTRAINT_TYPE_SIZELIKE, /* type */ + sizeof(bSizeLikeConstraint), /* size */ + "Copy Scale", /* name */ + "bSizeLikeConstraint", /* struct name */ + NULL, /* free data */ + sizelike_id_looper, /* id looper */ + NULL, /* copy data */ + sizelike_new_data, /* new data */ + sizelike_get_tars, /* get constraint targets */ + sizelike_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + sizelike_evaluate, /* evaluate */ }; /* ----------- Copy Transforms ------------- */ static void translike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bTransLikeConstraint *data = con->data; + bTransLikeConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int translike_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bTransLikeConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bTransLikeConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void translike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bTransLikeConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bTransLikeConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } static void translike_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets) { - bConstraintTarget *ct = targets->first; + bConstraintTarget *ct = targets->first; - if (VALID_CONS_TARGET(ct)) { - /* just copy the entire transform matrix of the target */ - copy_m4_m4(cob->matrix, ct->matrix); - } + if (VALID_CONS_TARGET(ct)) { + /* just copy the entire transform matrix of the target */ + copy_m4_m4(cob->matrix, ct->matrix); + } } static bConstraintTypeInfo CTI_TRANSLIKE = { - CONSTRAINT_TYPE_TRANSLIKE, /* type */ - sizeof(bTransLikeConstraint), /* size */ - "Copy Transforms", /* name */ - "bTransLikeConstraint", /* struct name */ - NULL, /* free data */ - translike_id_looper, /* id looper */ - NULL, /* copy data */ - NULL, /* new data */ - translike_get_tars, /* get constraint targets */ - translike_flush_tars, /* flush constraint targets */ - default_get_tarmat_full_bbone, /* get target matrix */ - translike_evaluate, /* evaluate */ + CONSTRAINT_TYPE_TRANSLIKE, /* type */ + sizeof(bTransLikeConstraint), /* size */ + "Copy Transforms", /* name */ + "bTransLikeConstraint", /* struct name */ + NULL, /* free data */ + translike_id_looper, /* id looper */ + NULL, /* copy data */ + NULL, /* new data */ + translike_get_tars, /* get constraint targets */ + translike_flush_tars, /* flush constraint targets */ + default_get_tarmat_full_bbone, /* get target matrix */ + translike_evaluate, /* evaluate */ }; /* ---------- Maintain Volume ---------- */ static void samevolume_new_data(void *cdata) { - bSameVolumeConstraint *data = (bSameVolumeConstraint *)cdata; + bSameVolumeConstraint *data = (bSameVolumeConstraint *)cdata; - data->flag = SAMEVOL_Y; - data->volume = 1.0f; + data->flag = SAMEVOL_Y; + data->volume = 1.0f; } static void samevolume_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) { - bSameVolumeConstraint *data = con->data; + bSameVolumeConstraint *data = con->data; - float volume = data->volume; - float fac = 1.0f, total_scale; - float obsize[3]; + float volume = data->volume; + float fac = 1.0f, total_scale; + float obsize[3]; - mat4_to_size(obsize, cob->matrix); + mat4_to_size(obsize, cob->matrix); - /* calculate normalizing scale factor for non-essential values */ - total_scale = obsize[0] * obsize[1] * obsize[2]; - if (total_scale != 0) - fac = sqrtf(volume / total_scale); + /* calculate normalizing scale factor for non-essential values */ + total_scale = obsize[0] * obsize[1] * obsize[2]; + if (total_scale != 0) + fac = sqrtf(volume / total_scale); - /* apply scaling factor to the channels not being kept */ - switch (data->flag) { - case SAMEVOL_X: - mul_v3_fl(cob->matrix[1], fac); - mul_v3_fl(cob->matrix[2], fac); - break; - case SAMEVOL_Y: - mul_v3_fl(cob->matrix[0], fac); - mul_v3_fl(cob->matrix[2], fac); - break; - case SAMEVOL_Z: - mul_v3_fl(cob->matrix[0], fac); - mul_v3_fl(cob->matrix[1], fac); - break; - } + /* apply scaling factor to the channels not being kept */ + switch (data->flag) { + case SAMEVOL_X: + mul_v3_fl(cob->matrix[1], fac); + mul_v3_fl(cob->matrix[2], fac); + break; + case SAMEVOL_Y: + mul_v3_fl(cob->matrix[0], fac); + mul_v3_fl(cob->matrix[2], fac); + break; + case SAMEVOL_Z: + mul_v3_fl(cob->matrix[0], fac); + mul_v3_fl(cob->matrix[1], fac); + break; + } } static bConstraintTypeInfo CTI_SAMEVOL = { - CONSTRAINT_TYPE_SAMEVOL, /* type */ - sizeof(bSameVolumeConstraint), /* size */ - "Maintain Volume", /* name */ - "bSameVolumeConstraint", /* struct name */ - NULL, /* free data */ - NULL, /* id looper */ - NULL, /* copy data */ - samevolume_new_data, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ - NULL, /* get target matrix */ - samevolume_evaluate, /* evaluate */ + CONSTRAINT_TYPE_SAMEVOL, /* type */ + sizeof(bSameVolumeConstraint), /* size */ + "Maintain Volume", /* name */ + "bSameVolumeConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* id looper */ + NULL, /* copy data */ + samevolume_new_data, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + samevolume_evaluate, /* evaluate */ }; /* ----------- Python Constraint -------------- */ static void pycon_free(bConstraint *con) { - bPythonConstraint *data = con->data; + bPythonConstraint *data = con->data; - /* id-properties */ - IDP_FreeProperty(data->prop); - MEM_freeN(data->prop); + /* id-properties */ + IDP_FreeProperty(data->prop); + MEM_freeN(data->prop); - /* multiple targets */ - BLI_freelistN(&data->targets); + /* multiple targets */ + BLI_freelistN(&data->targets); } static void pycon_copy(bConstraint *con, bConstraint *srccon) { - bPythonConstraint *pycon = (bPythonConstraint *)con->data; - bPythonConstraint *opycon = (bPythonConstraint *)srccon->data; + bPythonConstraint *pycon = (bPythonConstraint *)con->data; + bPythonConstraint *opycon = (bPythonConstraint *)srccon->data; - pycon->prop = IDP_CopyProperty(opycon->prop); - BLI_duplicatelist(&pycon->targets, &opycon->targets); + pycon->prop = IDP_CopyProperty(opycon->prop); + BLI_duplicatelist(&pycon->targets, &opycon->targets); } static void pycon_new_data(void *cdata) { - bPythonConstraint *data = (bPythonConstraint *)cdata; + bPythonConstraint *data = (bPythonConstraint *)cdata; - /* everything should be set correctly by calloc, except for the prop->type constant.*/ - data->prop = MEM_callocN(sizeof(IDProperty), "PyConstraintProps"); - data->prop->type = IDP_GROUP; + /* everything should be set correctly by calloc, except for the prop->type constant.*/ + data->prop = MEM_callocN(sizeof(IDProperty), "PyConstraintProps"); + data->prop->type = IDP_GROUP; } static int pycon_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bPythonConstraint *data = con->data; + if (con && list) { + bPythonConstraint *data = con->data; - list->first = data->targets.first; - list->last = data->targets.last; + list->first = data->targets.first; + list->last = data->targets.last; - return data->tarnum; - } + return data->tarnum; + } - return 0; + return 0; } static void pycon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bPythonConstraint *data = con->data; - bConstraintTarget *ct; + bPythonConstraint *data = con->data; + bConstraintTarget *ct; - /* targets */ - for (ct = data->targets.first; ct; ct = ct->next) - func(con, (ID **)&ct->tar, false, userdata); + /* targets */ + for (ct = data->targets.first; ct; ct = ct->next) + func(con, (ID **)&ct->tar, false, userdata); - /* script */ - func(con, (ID **)&data->text, true, userdata); + /* script */ + func(con, (ID **)&data->text, true, userdata); } /* Whether this approach is maintained remains to be seen (aligorith) */ static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), - bConstraint *con, bConstraintOb *UNUSED(cob), - bConstraintTarget *ct, float UNUSED(ctime)) + bConstraint *con, + bConstraintOb *UNUSED(cob), + bConstraintTarget *ct, + float UNUSED(ctime)) { #ifdef WITH_PYTHON - bPythonConstraint *data = con->data; + bPythonConstraint *data = con->data; #endif - if (VALID_CONS_TARGET(ct)) { - if (ct->tar->type == OB_CURVE && ct->tar->runtime.curve_cache == NULL) { - unit_m4(ct->matrix); - return; - } - - /* firstly calculate the matrix the normal way, then let the py-function override - * 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); - - /* only execute target calculation if allowed */ + if (VALID_CONS_TARGET(ct)) { + if (ct->tar->type == OB_CURVE && ct->tar->runtime.curve_cache == NULL) { + unit_m4(ct->matrix); + return; + } + + /* firstly calculate the matrix the normal way, then let the py-function override + * 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); + + /* only execute target calculation if allowed */ #ifdef WITH_PYTHON - if (G.f & G_FLAG_SCRIPT_AUTOEXEC) - BPY_pyconstraint_target(data, ct); + if (G.f & G_FLAG_SCRIPT_AUTOEXEC) + BPY_pyconstraint_target(data, ct); #endif - } - else if (ct) - unit_m4(ct->matrix); + } + else if (ct) + unit_m4(ct->matrix); } static void pycon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { #ifndef WITH_PYTHON - UNUSED_VARS(con, cob, targets); - return; + UNUSED_VARS(con, cob, targets); + return; #else - bPythonConstraint *data = con->data; + bPythonConstraint *data = con->data; - /* only evaluate in python if we're allowed to do so */ - if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0) return; + /* only evaluate in python if we're allowed to do so */ + if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0) + return; - /* Now, run the actual 'constraint' function, which should only access the matrices */ - BPY_pyconstraint_exec(data, cob, targets); + /* Now, run the actual 'constraint' function, which should only access the matrices */ + BPY_pyconstraint_exec(data, cob, targets); #endif /* WITH_PYTHON */ } static bConstraintTypeInfo CTI_PYTHON = { - CONSTRAINT_TYPE_PYTHON, /* type */ - sizeof(bPythonConstraint), /* size */ - "Script", /* name */ - "bPythonConstraint", /* struct name */ - pycon_free, /* free data */ - pycon_id_looper, /* id looper */ - pycon_copy, /* copy data */ - pycon_new_data, /* new data */ - pycon_get_tars, /* get constraint targets */ - NULL, /* flush constraint targets */ - pycon_get_tarmat, /* get target matrix */ - pycon_evaluate, /* evaluate */ + CONSTRAINT_TYPE_PYTHON, /* type */ + sizeof(bPythonConstraint), /* size */ + "Script", /* name */ + "bPythonConstraint", /* struct name */ + pycon_free, /* free data */ + pycon_id_looper, /* id looper */ + pycon_copy, /* copy data */ + pycon_new_data, /* new data */ + pycon_get_tars, /* get constraint targets */ + NULL, /* flush constraint targets */ + pycon_get_tarmat, /* get target matrix */ + pycon_evaluate, /* evaluate */ }; /* ----------- Armature Constraint -------------- */ static void armdef_free(bConstraint *con) { - bArmatureConstraint *data = con->data; + bArmatureConstraint *data = con->data; - /* Target list. */ - BLI_freelistN(&data->targets); + /* Target list. */ + BLI_freelistN(&data->targets); } static void armdef_copy(bConstraint *con, bConstraint *srccon) { - bArmatureConstraint *pcon = (bArmatureConstraint *)con->data; - bArmatureConstraint *opcon = (bArmatureConstraint *)srccon->data; + bArmatureConstraint *pcon = (bArmatureConstraint *)con->data; + bArmatureConstraint *opcon = (bArmatureConstraint *)srccon->data; - BLI_duplicatelist(&pcon->targets, &opcon->targets); + BLI_duplicatelist(&pcon->targets, &opcon->targets); } static int armdef_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bArmatureConstraint *data = con->data; + if (con && list) { + bArmatureConstraint *data = con->data; - *list = data->targets; + *list = data->targets; - return BLI_listbase_count(&data->targets); - } + return BLI_listbase_count(&data->targets); + } - return 0; + return 0; } static void armdef_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bArmatureConstraint *data = con->data; - bConstraintTarget *ct; + bArmatureConstraint *data = con->data; + bConstraintTarget *ct; - /* Target list. */ - for (ct = data->targets.first; ct; ct = ct->next) { - func(con, (ID **)&ct->tar, false, userdata); - } + /* Target list. */ + for (ct = data->targets.first; ct; ct = ct->next) { + func(con, (ID **)&ct->tar, false, userdata); + } } /* Compute the world space pose matrix of the target bone. */ static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph), - bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob), - bConstraintTarget *ct, float UNUSED(ctime)) + bConstraint *UNUSED(con), + bConstraintOb *UNUSED(cob), + bConstraintTarget *ct, + float UNUSED(ctime)) { - if (ct != NULL) { - if (ct->tar && ct->tar->type == OB_ARMATURE) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); + if (ct != NULL) { + if (ct->tar && ct->tar->type == OB_ARMATURE) { + bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); - if (pchan != NULL) { - mul_m4_m4m4(ct->matrix, ct->tar->obmat, pchan->pose_mat); - return; - } - } + if (pchan != NULL) { + mul_m4_m4m4(ct->matrix, ct->tar->obmat, pchan->pose_mat); + return; + } + } - unit_m4(ct->matrix); - } + unit_m4(ct->matrix); + } } -static void armdef_accumulate_matrix(float obmat[4][4], float iobmat[4][4], float basemat[4][4], float bonemat[4][4], float weight, float r_sum_mat[4][4], DualQuat *r_sum_dq) +static void armdef_accumulate_matrix(float obmat[4][4], + float iobmat[4][4], + float basemat[4][4], + float bonemat[4][4], + float weight, + float r_sum_mat[4][4], + DualQuat *r_sum_dq) { - if (weight == 0.0f) - return; + if (weight == 0.0f) + return; - /* Convert the selected matrix into object space. */ - float mat[4][4]; - mul_m4_series(mat, obmat, bonemat, iobmat); + /* Convert the selected matrix into object space. */ + float mat[4][4]; + mul_m4_series(mat, obmat, bonemat, iobmat); - /* Accumulate the transformation. */ - if (r_sum_dq != NULL) { - DualQuat tmpdq; + /* Accumulate the transformation. */ + if (r_sum_dq != NULL) { + DualQuat tmpdq; - mat4_to_dquat(&tmpdq, basemat, mat); - add_weighted_dq_dq(r_sum_dq, &tmpdq, weight); - } - else { - madd_m4_m4m4fl(r_sum_mat, r_sum_mat, mat, weight); - } + mat4_to_dquat(&tmpdq, basemat, mat); + add_weighted_dq_dq(r_sum_dq, &tmpdq, weight); + } + else { + madd_m4_m4m4fl(r_sum_mat, r_sum_mat, mat, weight); + } } /* Compute and accumulate transformation for a single target bone. */ -static void armdef_accumulate_bone(bConstraintTarget *ct, bPoseChannel *pchan, const float wco[3], bool force_envelope, float *r_totweight, float r_sum_mat[4][4], DualQuat *r_sum_dq) -{ - float iobmat[4][4], basemat[4][4], co[3]; - Bone *bone = pchan->bone; - float weight = ct->weight; - - /* Our object's location in target pose space. */ - invert_m4_m4(iobmat, ct->tar->obmat); - mul_v3_m4v3(co, iobmat, wco); - - /* Multiply by the envelope weight when appropriate. */ - if (force_envelope || (bone->flag & BONE_MULT_VG_ENV)) { - weight *= distfactor_to_bone(co, bone->arm_head, bone->arm_tail, - bone->rad_head, bone->rad_tail, bone->dist); - } - - /* Compute the quaternion base matrix. */ - if (r_sum_dq != NULL) { - mul_m4_series(basemat, ct->tar->obmat, bone->arm_mat, iobmat); - } - - /* Find the correct bone transform matrix in world space. */ - if (bone->segments > 1 && bone->segments == pchan->runtime.bbone_segments) { - Mat4 *b_bone_mats = pchan->runtime.bbone_deform_mats; - float (*iamat)[4] = b_bone_mats[0].mat; - - /* The target is a B-Bone: - * FIRST: find the segment (see b_bone_deform in armature.c) - * Need to transform co back to bonespace, only need y. */ - float y = iamat[0][1] * co[0] + iamat[1][1] * co[1] + iamat[2][1] * co[2] + iamat[3][1]; - - /* Blend the matrix. */ - int index; - float blend; - BKE_pchan_bbone_deform_segment_index(pchan, y / bone->length, &index, &blend); - - armdef_accumulate_matrix(ct->tar->obmat, iobmat, basemat, b_bone_mats[index + 1].mat, weight * (1.0f - blend), r_sum_mat, r_sum_dq); - armdef_accumulate_matrix(ct->tar->obmat, iobmat, basemat, b_bone_mats[index + 2].mat, weight * blend, r_sum_mat, r_sum_dq); - } - else { - /* Simple bone. This requires DEG_OPCODE_BONE_DONE dependency due to chan_mat. */ - armdef_accumulate_matrix(ct->tar->obmat, iobmat, basemat, pchan->chan_mat, weight, r_sum_mat, r_sum_dq); - } - - /* Accumulate the weight. */ - *r_totweight += weight; +static void armdef_accumulate_bone(bConstraintTarget *ct, + bPoseChannel *pchan, + const float wco[3], + bool force_envelope, + float *r_totweight, + float r_sum_mat[4][4], + DualQuat *r_sum_dq) +{ + float iobmat[4][4], basemat[4][4], co[3]; + Bone *bone = pchan->bone; + float weight = ct->weight; + + /* Our object's location in target pose space. */ + invert_m4_m4(iobmat, ct->tar->obmat); + mul_v3_m4v3(co, iobmat, wco); + + /* Multiply by the envelope weight when appropriate. */ + if (force_envelope || (bone->flag & BONE_MULT_VG_ENV)) { + weight *= distfactor_to_bone( + co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); + } + + /* Compute the quaternion base matrix. */ + if (r_sum_dq != NULL) { + mul_m4_series(basemat, ct->tar->obmat, bone->arm_mat, iobmat); + } + + /* Find the correct bone transform matrix in world space. */ + if (bone->segments > 1 && bone->segments == pchan->runtime.bbone_segments) { + Mat4 *b_bone_mats = pchan->runtime.bbone_deform_mats; + float(*iamat)[4] = b_bone_mats[0].mat; + + /* The target is a B-Bone: + * FIRST: find the segment (see b_bone_deform in armature.c) + * Need to transform co back to bonespace, only need y. */ + float y = iamat[0][1] * co[0] + iamat[1][1] * co[1] + iamat[2][1] * co[2] + iamat[3][1]; + + /* Blend the matrix. */ + int index; + float blend; + BKE_pchan_bbone_deform_segment_index(pchan, y / bone->length, &index, &blend); + + armdef_accumulate_matrix(ct->tar->obmat, + iobmat, + basemat, + b_bone_mats[index + 1].mat, + weight * (1.0f - blend), + r_sum_mat, + r_sum_dq); + armdef_accumulate_matrix(ct->tar->obmat, + iobmat, + basemat, + b_bone_mats[index + 2].mat, + weight * blend, + r_sum_mat, + r_sum_dq); + } + else { + /* Simple bone. This requires DEG_OPCODE_BONE_DONE dependency due to chan_mat. */ + armdef_accumulate_matrix( + ct->tar->obmat, iobmat, basemat, pchan->chan_mat, weight, r_sum_mat, r_sum_dq); + } + + /* Accumulate the weight. */ + *r_totweight += weight; } static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bArmatureConstraint *data = con->data; + bArmatureConstraint *data = con->data; - float sum_mat[4][4], input_co[3]; - DualQuat sum_dq; - float weight = 0.0f; + float sum_mat[4][4], input_co[3]; + DualQuat sum_dq; + float weight = 0.0f; - /* Prepare for blending. */ - zero_m4(sum_mat); - memset(&sum_dq, 0, sizeof(sum_dq)); + /* Prepare for blending. */ + zero_m4(sum_mat); + memset(&sum_dq, 0, sizeof(sum_dq)); - DualQuat *pdq = (data->flag & CONSTRAINT_ARMATURE_QUATERNION) ? &sum_dq : NULL; - bool use_envelopes = (data->flag & CONSTRAINT_ARMATURE_ENVELOPE) != 0; + DualQuat *pdq = (data->flag & CONSTRAINT_ARMATURE_QUATERNION) ? &sum_dq : NULL; + bool use_envelopes = (data->flag & CONSTRAINT_ARMATURE_ENVELOPE) != 0; - if (cob->pchan && cob->pchan->bone && !(data->flag & CONSTRAINT_ARMATURE_CUR_LOCATION)) { - /* For constraints on bones, use the rest position to bind b-bone segments - * and envelopes, to allow safely changing the bone location as if parented. */ - copy_v3_v3(input_co, cob->pchan->bone->arm_head); - mul_m4_v3(cob->ob->obmat, input_co); - } - else { - copy_v3_v3(input_co, cob->matrix[3]); - } + if (cob->pchan && cob->pchan->bone && !(data->flag & CONSTRAINT_ARMATURE_CUR_LOCATION)) { + /* For constraints on bones, use the rest position to bind b-bone segments + * and envelopes, to allow safely changing the bone location as if parented. */ + copy_v3_v3(input_co, cob->pchan->bone->arm_head); + mul_m4_v3(cob->ob->obmat, input_co); + } + else { + copy_v3_v3(input_co, cob->matrix[3]); + } - /* Process all targets. */ - for (bConstraintTarget *ct = targets->first; ct; ct = ct->next) { - if (ct->weight <= 0.0f) { - continue; - } + /* Process all targets. */ + for (bConstraintTarget *ct = targets->first; ct; ct = ct->next) { + if (ct->weight <= 0.0f) { + continue; + } - /* Lookup the bone and abort if failed. */ - if (!VALID_CONS_TARGET(ct) || ct->tar->type != OB_ARMATURE) { - return; - } + /* Lookup the bone and abort if failed. */ + if (!VALID_CONS_TARGET(ct) || ct->tar->type != OB_ARMATURE) { + return; + } - bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); + bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); - if (pchan == NULL || pchan->bone == NULL) { - return; - } + if (pchan == NULL || pchan->bone == NULL) { + return; + } - armdef_accumulate_bone(ct, pchan, input_co, use_envelopes, &weight, sum_mat, pdq); - } + armdef_accumulate_bone(ct, pchan, input_co, use_envelopes, &weight, sum_mat, pdq); + } - /* Compute the final transform. */ - if (weight > 0.0f) { - if (pdq != NULL) { - normalize_dq(pdq, weight); - dquat_to_mat4(sum_mat, pdq); - } - else { - mul_m4_fl(sum_mat, 1.0f / weight); - } + /* Compute the final transform. */ + if (weight > 0.0f) { + if (pdq != NULL) { + normalize_dq(pdq, weight); + dquat_to_mat4(sum_mat, pdq); + } + else { + mul_m4_fl(sum_mat, 1.0f / weight); + } - /* Apply the transform to the result matrix. */ - mul_m4_m4m4(cob->matrix, sum_mat, cob->matrix); - } + /* Apply the transform to the result matrix. */ + mul_m4_m4m4(cob->matrix, sum_mat, cob->matrix); + } } static bConstraintTypeInfo CTI_ARMATURE = { - CONSTRAINT_TYPE_ARMATURE, /* type */ - sizeof(bArmatureConstraint), /* size */ - "Armature", /* name */ - "bArmatureConstraint", /* struct name */ - armdef_free, /* free data */ - armdef_id_looper, /* id looper */ - armdef_copy, /* copy data */ - NULL, /* new data */ - armdef_get_tars, /* get constraint targets */ - NULL, /* flush constraint targets */ - armdef_get_tarmat, /* get target matrix */ - armdef_evaluate, /* evaluate */ + CONSTRAINT_TYPE_ARMATURE, /* type */ + sizeof(bArmatureConstraint), /* size */ + "Armature", /* name */ + "bArmatureConstraint", /* struct name */ + armdef_free, /* free data */ + armdef_id_looper, /* id looper */ + armdef_copy, /* copy data */ + NULL, /* new data */ + armdef_get_tars, /* get constraint targets */ + NULL, /* flush constraint targets */ + armdef_get_tarmat, /* get target matrix */ + armdef_evaluate, /* evaluate */ }; /* -------- Action Constraint ----------- */ static void actcon_new_data(void *cdata) { - bActionConstraint *data = (bActionConstraint *)cdata; + bActionConstraint *data = (bActionConstraint *)cdata; - /* set type to 20 (Loc X), as 0 is Rot X for backwards compatibility */ - data->type = 20; + /* set type to 20 (Loc X), as 0 is Rot X for backwards compatibility */ + data->type = 20; } static void actcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bActionConstraint *data = con->data; + bActionConstraint *data = con->data; - /* target */ - func(con, (ID **)&data->tar, false, userdata); + /* target */ + func(con, (ID **)&data->tar, false, userdata); - /* action */ - func(con, (ID **)&data->act, true, userdata); + /* action */ + func(con, (ID **)&data->act, true, userdata); } static int actcon_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bActionConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bActionConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bActionConstraint *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, no_copy); - } -} - -static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) -{ - bActionConstraint *data = con->data; - - if (VALID_CONS_TARGET(ct)) { - float tempmat[4][4], vec[3]; - float s, t; - short axis; - - /* initialize return matrix */ - unit_m4(ct->matrix); - - /* 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); - - /* determine where in transform range target is */ - /* data->type is mapped as follows for backwards compatibility: - * 00,01,02 - rotation (it used to be like this) - * 10,11,12 - scaling - * 20,21,22 - location - */ - if (data->type < 10) { - /* extract rotation (is in whatever space target should be in) */ - mat4_to_eul(vec, tempmat); - mul_v3_fl(vec, RAD2DEGF(1.0f)); /* rad -> deg */ - axis = data->type; - } - else if (data->type < 20) { - /* extract scaling (is in whatever space target should be in) */ - mat4_to_size(vec, tempmat); - axis = data->type - 10; - } - else { - /* extract location */ - copy_v3_v3(vec, tempmat[3]); - axis = data->type - 20; - } - - BLI_assert((unsigned int)axis < 3); - - /* Target defines the animation */ - s = (vec[axis] - data->min) / (data->max - data->min); - CLAMP(s, 0, 1); - t = (s * (data->end - data->start)) + data->start; - - if (G.debug & G_DEBUG) - printf("do Action Constraint %s - Ob %s Pchan %s\n", con->name, cob->ob->id.name + 2, (cob->pchan) ? cob->pchan->name : NULL); - - /* Get the appropriate information from the action */ - if (cob->type == CONSTRAINT_OBTYPE_OBJECT || (data->flag & ACTCON_BONE_USE_OBJECT_ACTION)) { - Object workob; - - /* evaluate using workob */ - /* FIXME: we don't have any consistent standards on limiting effects on object... */ - what_does_obaction(cob->ob, &workob, NULL, data->act, NULL, t); - BKE_object_to_mat4(&workob, ct->matrix); - } - else if (cob->type == CONSTRAINT_OBTYPE_BONE) { - Object workob; - bPose pose = {{0}}; - bPoseChannel *pchan, *tchan; - - /* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set - * - we need to manually copy over a few settings, including rotation order, otherwise this fails - */ - pchan = cob->pchan; - - tchan = BKE_pose_channel_verify(&pose, pchan->name); - tchan->rotmode = pchan->rotmode; - - /* evaluate action using workob (it will only set the PoseChannel in question) */ - what_does_obaction(cob->ob, &workob, &pose, data->act, pchan->name, t); - - /* convert animation to matrices for use here */ - BKE_pchan_calc_mat(tchan); - copy_m4_m4(ct->matrix, tchan->chan_mat); - - /* Clean up */ - BKE_pose_free_data(&pose); - } - else { - /* behavior undefined... */ - puts("Error: unknown owner type for Action Constraint"); - } - } + if (con && list) { + bActionConstraint *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, no_copy); + } +} + +static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), + bConstraint *con, + bConstraintOb *cob, + bConstraintTarget *ct, + float UNUSED(ctime)) +{ + bActionConstraint *data = con->data; + + if (VALID_CONS_TARGET(ct)) { + float tempmat[4][4], vec[3]; + float s, t; + short axis; + + /* initialize return matrix */ + unit_m4(ct->matrix); + + /* 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); + + /* determine where in transform range target is */ + /* data->type is mapped as follows for backwards compatibility: + * 00,01,02 - rotation (it used to be like this) + * 10,11,12 - scaling + * 20,21,22 - location + */ + if (data->type < 10) { + /* extract rotation (is in whatever space target should be in) */ + mat4_to_eul(vec, tempmat); + mul_v3_fl(vec, RAD2DEGF(1.0f)); /* rad -> deg */ + axis = data->type; + } + else if (data->type < 20) { + /* extract scaling (is in whatever space target should be in) */ + mat4_to_size(vec, tempmat); + axis = data->type - 10; + } + else { + /* extract location */ + copy_v3_v3(vec, tempmat[3]); + axis = data->type - 20; + } + + BLI_assert((unsigned int)axis < 3); + + /* Target defines the animation */ + s = (vec[axis] - data->min) / (data->max - data->min); + CLAMP(s, 0, 1); + t = (s * (data->end - data->start)) + data->start; + + if (G.debug & G_DEBUG) + printf("do Action Constraint %s - Ob %s Pchan %s\n", + con->name, + cob->ob->id.name + 2, + (cob->pchan) ? cob->pchan->name : NULL); + + /* Get the appropriate information from the action */ + if (cob->type == CONSTRAINT_OBTYPE_OBJECT || (data->flag & ACTCON_BONE_USE_OBJECT_ACTION)) { + Object workob; + + /* evaluate using workob */ + /* FIXME: we don't have any consistent standards on limiting effects on object... */ + what_does_obaction(cob->ob, &workob, NULL, data->act, NULL, t); + BKE_object_to_mat4(&workob, ct->matrix); + } + else if (cob->type == CONSTRAINT_OBTYPE_BONE) { + Object workob; + bPose pose = {{0}}; + bPoseChannel *pchan, *tchan; + + /* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set + * - we need to manually copy over a few settings, including rotation order, otherwise this fails + */ + pchan = cob->pchan; + + tchan = BKE_pose_channel_verify(&pose, pchan->name); + tchan->rotmode = pchan->rotmode; + + /* evaluate action using workob (it will only set the PoseChannel in question) */ + what_does_obaction(cob->ob, &workob, &pose, data->act, pchan->name, t); + + /* convert animation to matrices for use here */ + BKE_pchan_calc_mat(tchan); + copy_m4_m4(ct->matrix, tchan->chan_mat); + + /* Clean up */ + BKE_pose_free_data(&pose); + } + else { + /* behavior undefined... */ + puts("Error: unknown owner type for Action Constraint"); + } + } } static void actcon_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets) { - bConstraintTarget *ct = targets->first; + bConstraintTarget *ct = targets->first; - if (VALID_CONS_TARGET(ct)) { - float temp[4][4]; + if (VALID_CONS_TARGET(ct)) { + float temp[4][4]; - /* Nice and simple... we just need to multiply the matrices, as the get_target_matrix - * function has already taken care of everything else. - */ - copy_m4_m4(temp, cob->matrix); - mul_m4_m4m4(cob->matrix, temp, ct->matrix); - } + /* Nice and simple... we just need to multiply the matrices, as the get_target_matrix + * function has already taken care of everything else. + */ + copy_m4_m4(temp, cob->matrix); + mul_m4_m4m4(cob->matrix, temp, ct->matrix); + } } static bConstraintTypeInfo CTI_ACTION = { - CONSTRAINT_TYPE_ACTION, /* type */ - sizeof(bActionConstraint), /* size */ - "Action", /* name */ - "bActionConstraint", /* struct name */ - NULL, /* free data */ - actcon_id_looper, /* id looper */ - NULL, /* copy data */ - actcon_new_data, /* new data */ - actcon_get_tars, /* get constraint targets */ - actcon_flush_tars, /* flush constraint targets */ - actcon_get_tarmat, /* get target matrix */ - actcon_evaluate, /* evaluate */ + CONSTRAINT_TYPE_ACTION, /* type */ + sizeof(bActionConstraint), /* size */ + "Action", /* name */ + "bActionConstraint", /* struct name */ + NULL, /* free data */ + actcon_id_looper, /* id looper */ + NULL, /* copy data */ + actcon_new_data, /* new data */ + actcon_get_tars, /* get constraint targets */ + actcon_flush_tars, /* flush constraint targets */ + actcon_get_tarmat, /* get target matrix */ + actcon_evaluate, /* evaluate */ }; /* --------- Locked Track ---------- */ static void locktrack_new_data(void *cdata) { - bLockTrackConstraint *data = (bLockTrackConstraint *)cdata; + bLockTrackConstraint *data = (bLockTrackConstraint *)cdata; - data->trackflag = TRACK_Y; - data->lockflag = LOCK_Z; + data->trackflag = TRACK_Y; + data->lockflag = LOCK_Z; } static void locktrack_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bLockTrackConstraint *data = con->data; + bLockTrackConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int locktrack_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bLockTrackConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bLockTrackConstraint *data = con->data; + bConstraintTarget *ct; - /* the following macro is used for all standard single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void locktrack_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bLockTrackConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bLockTrackConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } static void locktrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bLockTrackConstraint *data = con->data; - bConstraintTarget *ct = targets->first; - - if (VALID_CONS_TARGET(ct)) { - float vec[3], vec2[3]; - float totmat[3][3]; - float tmpmat[3][3]; - float invmat[3][3]; - float mdet; - - /* Vector object -> target */ - sub_v3_v3v3(vec, ct->matrix[3], cob->matrix[3]); - switch (data->lockflag) { - case LOCK_X: /* LOCK X */ - { - switch (data->trackflag) { - case TRACK_Y: /* LOCK X TRACK Y */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[0]); - sub_v3_v3v3(totmat[1], vec, vec2); - normalize_v3(totmat[1]); - - /* the x axis is fixed */ - normalize_v3_v3(totmat[0], cob->matrix[0]); - - /* the z axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[2], totmat[0], totmat[1]); - break; - } - case TRACK_Z: /* LOCK X TRACK Z */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[0]); - sub_v3_v3v3(totmat[2], vec, vec2); - normalize_v3(totmat[2]); - - /* the x axis is fixed */ - normalize_v3_v3(totmat[0], cob->matrix[0]); - - /* the z axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[1], totmat[2], totmat[0]); - break; - } - case TRACK_nY: /* LOCK X TRACK -Y */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[0]); - sub_v3_v3v3(totmat[1], vec, vec2); - normalize_v3(totmat[1]); - negate_v3(totmat[1]); - - /* the x axis is fixed */ - normalize_v3_v3(totmat[0], cob->matrix[0]); - - /* the z axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[2], totmat[0], totmat[1]); - break; - } - case TRACK_nZ: /* LOCK X TRACK -Z */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[0]); - sub_v3_v3v3(totmat[2], vec, vec2); - normalize_v3(totmat[2]); - negate_v3(totmat[2]); - - /* the x axis is fixed */ - normalize_v3_v3(totmat[0], cob->matrix[0]); - - /* the z axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[1], totmat[2], totmat[0]); - break; - } - default: - { - unit_m3(totmat); - break; - } - } - break; - } - case LOCK_Y: /* LOCK Y */ - { - switch (data->trackflag) { - case TRACK_X: /* LOCK Y TRACK X */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[1]); - sub_v3_v3v3(totmat[0], vec, vec2); - normalize_v3(totmat[0]); - - /* the y axis is fixed */ - normalize_v3_v3(totmat[1], cob->matrix[1]); - - /* the z axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[2], totmat[0], totmat[1]); - break; - } - case TRACK_Z: /* LOCK Y TRACK Z */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[1]); - sub_v3_v3v3(totmat[2], vec, vec2); - normalize_v3(totmat[2]); - - /* the y axis is fixed */ - normalize_v3_v3(totmat[1], cob->matrix[1]); - - /* the z axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[0], totmat[1], totmat[2]); - break; - } - case TRACK_nX: /* LOCK Y TRACK -X */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[1]); - sub_v3_v3v3(totmat[0], vec, vec2); - normalize_v3(totmat[0]); - negate_v3(totmat[0]); - - /* the y axis is fixed */ - normalize_v3_v3(totmat[1], cob->matrix[1]); - - /* the z axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[2], totmat[0], totmat[1]); - break; - } - case TRACK_nZ: /* LOCK Y TRACK -Z */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[1]); - sub_v3_v3v3(totmat[2], vec, vec2); - normalize_v3(totmat[2]); - negate_v3(totmat[2]); - - /* the y axis is fixed */ - normalize_v3_v3(totmat[1], cob->matrix[1]); - - /* the z axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[0], totmat[1], totmat[2]); - break; - } - default: - { - unit_m3(totmat); - break; - } - } - break; - } - case LOCK_Z: /* LOCK Z */ - { - switch (data->trackflag) { - case TRACK_X: /* LOCK Z TRACK X */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[2]); - sub_v3_v3v3(totmat[0], vec, vec2); - normalize_v3(totmat[0]); - - /* the z axis is fixed */ - normalize_v3_v3(totmat[2], cob->matrix[2]); - - /* the x axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[1], totmat[2], totmat[0]); - break; - } - case TRACK_Y: /* LOCK Z TRACK Y */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[2]); - sub_v3_v3v3(totmat[1], vec, vec2); - normalize_v3(totmat[1]); - - /* the z axis is fixed */ - normalize_v3_v3(totmat[2], cob->matrix[2]); - - /* the x axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[0], totmat[1], totmat[2]); - break; - } - case TRACK_nX: /* LOCK Z TRACK -X */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[2]); - sub_v3_v3v3(totmat[0], vec, vec2); - normalize_v3(totmat[0]); - negate_v3(totmat[0]); - - /* the z axis is fixed */ - normalize_v3_v3(totmat[2], cob->matrix[2]); - - /* the x axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[1], totmat[2], totmat[0]); - break; - } - case TRACK_nY: /* LOCK Z TRACK -Y */ - { - /* Projection of Vector on the plane */ - project_v3_v3v3(vec2, vec, cob->matrix[2]); - sub_v3_v3v3(totmat[1], vec, vec2); - normalize_v3(totmat[1]); - negate_v3(totmat[1]); - - /* the z axis is fixed */ - normalize_v3_v3(totmat[2], cob->matrix[2]); - - /* the x axis gets mapped onto a third orthogonal vector */ - cross_v3_v3v3(totmat[0], totmat[1], totmat[2]); - break; - } - default: - { - unit_m3(totmat); - break; - } - } - break; - } - default: - { - unit_m3(totmat); - break; - } - } - /* Block to keep matrix heading */ - copy_m3_m4(tmpmat, cob->matrix); - normalize_m3(tmpmat); - invert_m3_m3(invmat, tmpmat); - mul_m3_m3m3(tmpmat, totmat, invmat); - totmat[0][0] = tmpmat[0][0]; totmat[0][1] = tmpmat[0][1]; totmat[0][2] = tmpmat[0][2]; - totmat[1][0] = tmpmat[1][0]; totmat[1][1] = tmpmat[1][1]; totmat[1][2] = tmpmat[1][2]; - totmat[2][0] = tmpmat[2][0]; totmat[2][1] = tmpmat[2][1]; totmat[2][2] = tmpmat[2][2]; - - mdet = determinant_m3(totmat[0][0], totmat[0][1], totmat[0][2], - totmat[1][0], totmat[1][1], totmat[1][2], - totmat[2][0], totmat[2][1], totmat[2][2]); - if (mdet == 0) { - unit_m3(totmat); - } - - /* apply out transformation to the object */ - mul_m4_m3m4(cob->matrix, totmat, cob->matrix); - } + bLockTrackConstraint *data = con->data; + bConstraintTarget *ct = targets->first; + + if (VALID_CONS_TARGET(ct)) { + float vec[3], vec2[3]; + float totmat[3][3]; + float tmpmat[3][3]; + float invmat[3][3]; + float mdet; + + /* Vector object -> target */ + sub_v3_v3v3(vec, ct->matrix[3], cob->matrix[3]); + switch (data->lockflag) { + case LOCK_X: /* LOCK X */ + { + switch (data->trackflag) { + case TRACK_Y: /* LOCK X TRACK Y */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[0]); + sub_v3_v3v3(totmat[1], vec, vec2); + normalize_v3(totmat[1]); + + /* the x axis is fixed */ + normalize_v3_v3(totmat[0], cob->matrix[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[2], totmat[0], totmat[1]); + break; + } + case TRACK_Z: /* LOCK X TRACK Z */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[0]); + sub_v3_v3v3(totmat[2], vec, vec2); + normalize_v3(totmat[2]); + + /* the x axis is fixed */ + normalize_v3_v3(totmat[0], cob->matrix[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[1], totmat[2], totmat[0]); + break; + } + case TRACK_nY: /* LOCK X TRACK -Y */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[0]); + sub_v3_v3v3(totmat[1], vec, vec2); + normalize_v3(totmat[1]); + negate_v3(totmat[1]); + + /* the x axis is fixed */ + normalize_v3_v3(totmat[0], cob->matrix[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[2], totmat[0], totmat[1]); + break; + } + case TRACK_nZ: /* LOCK X TRACK -Z */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[0]); + sub_v3_v3v3(totmat[2], vec, vec2); + normalize_v3(totmat[2]); + negate_v3(totmat[2]); + + /* the x axis is fixed */ + normalize_v3_v3(totmat[0], cob->matrix[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[1], totmat[2], totmat[0]); + break; + } + default: { + unit_m3(totmat); + break; + } + } + break; + } + case LOCK_Y: /* LOCK Y */ + { + switch (data->trackflag) { + case TRACK_X: /* LOCK Y TRACK X */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[1]); + sub_v3_v3v3(totmat[0], vec, vec2); + normalize_v3(totmat[0]); + + /* the y axis is fixed */ + normalize_v3_v3(totmat[1], cob->matrix[1]); + + /* the z axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[2], totmat[0], totmat[1]); + break; + } + case TRACK_Z: /* LOCK Y TRACK Z */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[1]); + sub_v3_v3v3(totmat[2], vec, vec2); + normalize_v3(totmat[2]); + + /* the y axis is fixed */ + normalize_v3_v3(totmat[1], cob->matrix[1]); + + /* the z axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[0], totmat[1], totmat[2]); + break; + } + case TRACK_nX: /* LOCK Y TRACK -X */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[1]); + sub_v3_v3v3(totmat[0], vec, vec2); + normalize_v3(totmat[0]); + negate_v3(totmat[0]); + + /* the y axis is fixed */ + normalize_v3_v3(totmat[1], cob->matrix[1]); + + /* the z axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[2], totmat[0], totmat[1]); + break; + } + case TRACK_nZ: /* LOCK Y TRACK -Z */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[1]); + sub_v3_v3v3(totmat[2], vec, vec2); + normalize_v3(totmat[2]); + negate_v3(totmat[2]); + + /* the y axis is fixed */ + normalize_v3_v3(totmat[1], cob->matrix[1]); + + /* the z axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[0], totmat[1], totmat[2]); + break; + } + default: { + unit_m3(totmat); + break; + } + } + break; + } + case LOCK_Z: /* LOCK Z */ + { + switch (data->trackflag) { + case TRACK_X: /* LOCK Z TRACK X */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[2]); + sub_v3_v3v3(totmat[0], vec, vec2); + normalize_v3(totmat[0]); + + /* the z axis is fixed */ + normalize_v3_v3(totmat[2], cob->matrix[2]); + + /* the x axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[1], totmat[2], totmat[0]); + break; + } + case TRACK_Y: /* LOCK Z TRACK Y */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[2]); + sub_v3_v3v3(totmat[1], vec, vec2); + normalize_v3(totmat[1]); + + /* the z axis is fixed */ + normalize_v3_v3(totmat[2], cob->matrix[2]); + + /* the x axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[0], totmat[1], totmat[2]); + break; + } + case TRACK_nX: /* LOCK Z TRACK -X */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[2]); + sub_v3_v3v3(totmat[0], vec, vec2); + normalize_v3(totmat[0]); + negate_v3(totmat[0]); + + /* the z axis is fixed */ + normalize_v3_v3(totmat[2], cob->matrix[2]); + + /* the x axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[1], totmat[2], totmat[0]); + break; + } + case TRACK_nY: /* LOCK Z TRACK -Y */ + { + /* Projection of Vector on the plane */ + project_v3_v3v3(vec2, vec, cob->matrix[2]); + sub_v3_v3v3(totmat[1], vec, vec2); + normalize_v3(totmat[1]); + negate_v3(totmat[1]); + + /* the z axis is fixed */ + normalize_v3_v3(totmat[2], cob->matrix[2]); + + /* the x axis gets mapped onto a third orthogonal vector */ + cross_v3_v3v3(totmat[0], totmat[1], totmat[2]); + break; + } + default: { + unit_m3(totmat); + break; + } + } + break; + } + default: { + unit_m3(totmat); + break; + } + } + /* Block to keep matrix heading */ + copy_m3_m4(tmpmat, cob->matrix); + normalize_m3(tmpmat); + invert_m3_m3(invmat, tmpmat); + mul_m3_m3m3(tmpmat, totmat, invmat); + totmat[0][0] = tmpmat[0][0]; + totmat[0][1] = tmpmat[0][1]; + totmat[0][2] = tmpmat[0][2]; + totmat[1][0] = tmpmat[1][0]; + totmat[1][1] = tmpmat[1][1]; + totmat[1][2] = tmpmat[1][2]; + totmat[2][0] = tmpmat[2][0]; + totmat[2][1] = tmpmat[2][1]; + totmat[2][2] = tmpmat[2][2]; + + mdet = determinant_m3(totmat[0][0], + totmat[0][1], + totmat[0][2], + totmat[1][0], + totmat[1][1], + totmat[1][2], + totmat[2][0], + totmat[2][1], + totmat[2][2]); + if (mdet == 0) { + unit_m3(totmat); + } + + /* apply out transformation to the object */ + mul_m4_m3m4(cob->matrix, totmat, cob->matrix); + } } static bConstraintTypeInfo CTI_LOCKTRACK = { - CONSTRAINT_TYPE_LOCKTRACK, /* type */ - sizeof(bLockTrackConstraint), /* size */ - "Locked Track", /* name */ - "bLockTrackConstraint", /* struct name */ - NULL, /* free data */ - locktrack_id_looper, /* id looper */ - NULL, /* copy data */ - locktrack_new_data, /* new data */ - locktrack_get_tars, /* get constraint targets */ - locktrack_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ - locktrack_evaluate, /* evaluate */ + CONSTRAINT_TYPE_LOCKTRACK, /* type */ + sizeof(bLockTrackConstraint), /* size */ + "Locked Track", /* name */ + "bLockTrackConstraint", /* struct name */ + NULL, /* free data */ + locktrack_id_looper, /* id looper */ + NULL, /* copy data */ + locktrack_new_data, /* new data */ + locktrack_get_tars, /* get constraint targets */ + locktrack_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + locktrack_evaluate, /* evaluate */ }; /* ---------- Limit Distance Constraint ----------- */ static void distlimit_new_data(void *cdata) { - bDistLimitConstraint *data = (bDistLimitConstraint *)cdata; + bDistLimitConstraint *data = (bDistLimitConstraint *)cdata; - data->dist = 0.0f; + data->dist = 0.0f; } static void distlimit_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bDistLimitConstraint *data = con->data; + bDistLimitConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int distlimit_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bDistLimitConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bDistLimitConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void distlimit_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bDistLimitConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bDistLimitConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } static void distlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bDistLimitConstraint *data = con->data; - bConstraintTarget *ct = targets->first; - - /* only evaluate if there is a target */ - if (VALID_CONS_TARGET(ct)) { - float dvec[3], dist, sfac = 1.0f; - short clamp_surf = 0; - - /* calculate our current distance from the target */ - dist = len_v3v3(cob->matrix[3], ct->matrix[3]); - - /* set distance (flag is only set when user demands it) */ - if (data->dist == 0) { - data->dist = dist; - - /* Write the computed distance back to the master copy if in COW evaluation. */ - bConstraint *orig_con = constraint_find_original_for_update(cob, con); - - if (orig_con != NULL) { - bDistLimitConstraint *orig_data = orig_con->data; - - orig_data->dist = data->dist; - } - } - - /* check if we're which way to clamp from, and calculate interpolation factor (if needed) */ - if (data->mode == LIMITDIST_OUTSIDE) { - /* if inside, then move to surface */ - if (dist <= data->dist) { - clamp_surf = 1; - if (dist != 0.0f) sfac = data->dist / dist; - } - /* if soft-distance is enabled, start fading once owner is dist+softdist from the target */ - else if (data->flag & LIMITDIST_USESOFT) { - if (dist <= (data->dist + data->soft)) { - /* pass */ - } - } - } - else if (data->mode == LIMITDIST_INSIDE) { - /* if outside, then move to surface */ - if (dist >= data->dist) { - clamp_surf = 1; - if (dist != 0.0f) sfac = data->dist / dist; - } - /* if soft-distance is enabled, start fading once owner is dist-soft from the target */ - else if (data->flag & LIMITDIST_USESOFT) { - /* FIXME: there's a problem with "jumping" when this kicks in */ - if (dist >= (data->dist - data->soft)) { - sfac = (float)(data->soft * (1.0f - expf(-(dist - data->dist) / data->soft)) + data->dist); - if (dist != 0.0f) sfac /= dist; - - clamp_surf = 1; - } - } - } - else { - if (IS_EQF(dist, data->dist) == 0) { - clamp_surf = 1; - if (dist != 0.0f) sfac = data->dist / dist; - } - } - - /* clamp to 'surface' (i.e. move owner so that dist == data->dist) */ - if (clamp_surf) { - /* simply interpolate along line formed by target -> owner */ - interp_v3_v3v3(dvec, ct->matrix[3], cob->matrix[3], sfac); - - /* copy new vector onto owner */ - copy_v3_v3(cob->matrix[3], dvec); - } - } + bDistLimitConstraint *data = con->data; + bConstraintTarget *ct = targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float dvec[3], dist, sfac = 1.0f; + short clamp_surf = 0; + + /* calculate our current distance from the target */ + dist = len_v3v3(cob->matrix[3], ct->matrix[3]); + + /* set distance (flag is only set when user demands it) */ + if (data->dist == 0) { + data->dist = dist; + + /* Write the computed distance back to the master copy if in COW evaluation. */ + bConstraint *orig_con = constraint_find_original_for_update(cob, con); + + if (orig_con != NULL) { + bDistLimitConstraint *orig_data = orig_con->data; + + orig_data->dist = data->dist; + } + } + + /* check if we're which way to clamp from, and calculate interpolation factor (if needed) */ + if (data->mode == LIMITDIST_OUTSIDE) { + /* if inside, then move to surface */ + if (dist <= data->dist) { + clamp_surf = 1; + if (dist != 0.0f) + sfac = data->dist / dist; + } + /* if soft-distance is enabled, start fading once owner is dist+softdist from the target */ + else if (data->flag & LIMITDIST_USESOFT) { + if (dist <= (data->dist + data->soft)) { + /* pass */ + } + } + } + else if (data->mode == LIMITDIST_INSIDE) { + /* if outside, then move to surface */ + if (dist >= data->dist) { + clamp_surf = 1; + if (dist != 0.0f) + sfac = data->dist / dist; + } + /* if soft-distance is enabled, start fading once owner is dist-soft from the target */ + else if (data->flag & LIMITDIST_USESOFT) { + /* FIXME: there's a problem with "jumping" when this kicks in */ + if (dist >= (data->dist - data->soft)) { + sfac = (float)(data->soft * (1.0f - expf(-(dist - data->dist) / data->soft)) + + data->dist); + if (dist != 0.0f) + sfac /= dist; + + clamp_surf = 1; + } + } + } + else { + if (IS_EQF(dist, data->dist) == 0) { + clamp_surf = 1; + if (dist != 0.0f) + sfac = data->dist / dist; + } + } + + /* clamp to 'surface' (i.e. move owner so that dist == data->dist) */ + if (clamp_surf) { + /* simply interpolate along line formed by target -> owner */ + interp_v3_v3v3(dvec, ct->matrix[3], cob->matrix[3], sfac); + + /* copy new vector onto owner */ + copy_v3_v3(cob->matrix[3], dvec); + } + } } static bConstraintTypeInfo CTI_DISTLIMIT = { - CONSTRAINT_TYPE_DISTLIMIT, /* type */ - sizeof(bDistLimitConstraint), /* size */ - "Limit Distance", /* name */ - "bDistLimitConstraint", /* struct name */ - NULL, /* free data */ - distlimit_id_looper, /* id looper */ - NULL, /* copy data */ - distlimit_new_data, /* new data */ - distlimit_get_tars, /* get constraint targets */ - distlimit_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get a target matrix */ - distlimit_evaluate, /* evaluate */ + CONSTRAINT_TYPE_DISTLIMIT, /* type */ + sizeof(bDistLimitConstraint), /* size */ + "Limit Distance", /* name */ + "bDistLimitConstraint", /* struct name */ + NULL, /* free data */ + distlimit_id_looper, /* id looper */ + NULL, /* copy data */ + distlimit_new_data, /* new data */ + distlimit_get_tars, /* get constraint targets */ + distlimit_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get a target matrix */ + distlimit_evaluate, /* evaluate */ }; /* ---------- Stretch To ------------ */ static void stretchto_new_data(void *cdata) { - bStretchToConstraint *data = (bStretchToConstraint *)cdata; + bStretchToConstraint *data = (bStretchToConstraint *)cdata; - data->volmode = 0; - data->plane = 0; - data->orglength = 0.0; - data->bulge = 1.0; - data->bulge_max = 1.0f; - data->bulge_min = 1.0f; + data->volmode = 0; + data->plane = 0; + data->orglength = 0.0; + data->bulge = 1.0; + data->bulge_max = 1.0f; + data->bulge_min = 1.0f; } static void stretchto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bStretchToConstraint *data = con->data; + bStretchToConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int stretchto_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bStretchToConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bStretchToConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void stretchto_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bStretchToConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bStretchToConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bStretchToConstraint *data = con->data; - bConstraintTarget *ct = targets->first; + bStretchToConstraint *data = con->data; + bConstraintTarget *ct = targets->first; - /* only evaluate if there is a target */ - if (VALID_CONS_TARGET(ct)) { - float size[3], scale[3], vec[3], xx[3], zz[3], orth[3]; - float totmat[3][3]; - float dist, bulge; + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float size[3], scale[3], vec[3], xx[3], zz[3], orth[3]; + float totmat[3][3]; + float dist, bulge; - /* store scaling before destroying obmat */ - mat4_to_size(size, cob->matrix); + /* store scaling before destroying obmat */ + mat4_to_size(size, cob->matrix); - /* store X orientation before destroying obmat */ - normalize_v3_v3(xx, cob->matrix[0]); + /* store X orientation before destroying obmat */ + normalize_v3_v3(xx, cob->matrix[0]); - /* store Z orientation before destroying obmat */ - normalize_v3_v3(zz, cob->matrix[2]); + /* store Z orientation before destroying obmat */ + normalize_v3_v3(zz, cob->matrix[2]); - /* XXX That makes the constraint buggy with asymmetrically scaled objects, see #29940. */ + /* XXX That makes the constraint buggy with asymmetrically scaled objects, see #29940. */ #if 0 - sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]); - vec[0] /= size[0]; - vec[1] /= size[1]; - vec[2] /= size[2]; + sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]); + vec[0] /= size[0]; + vec[1] /= size[1]; + vec[2] /= size[2]; - dist = normalize_v3(vec); + dist = normalize_v3(vec); #endif - dist = len_v3v3(cob->matrix[3], ct->matrix[3]); - /* Only Y constrained object axis scale should be used, to keep same length when scaling it. */ - dist /= size[1]; - - /* data->orglength==0 occurs on first run, and after 'R' button is clicked */ - if (data->orglength == 0) { - data->orglength = dist; - - /* Write the computed length back to the master copy if in COW evaluation. */ - bConstraint *orig_con = constraint_find_original_for_update(cob, con); - - if (orig_con != NULL) { - bStretchToConstraint *orig_data = orig_con->data; - - orig_data->orglength = data->orglength; - } - } - - scale[1] = dist / data->orglength; - - bulge = powf(data->orglength / dist, data->bulge); - - if (bulge > 1.0f) { - if (data->flag & STRETCHTOCON_USE_BULGE_MAX) { - float bulge_max = max_ff(data->bulge_max, 1.0f); - float hard = min_ff(bulge, bulge_max); - - float range = bulge_max - 1.0f; - float scale_fac = (range > 0.0f) ? 1.0f / range : 0.0f; - float soft = 1.0f + range * atanf((bulge - 1.0f) * scale_fac) / (float)M_PI_2; - - bulge = interpf(soft, hard, data->bulge_smooth); - } - } - if (bulge < 1.0f) { - if (data->flag & STRETCHTOCON_USE_BULGE_MIN) { - float bulge_min = CLAMPIS(data->bulge_min, 0.0f, 1.0f); - float hard = max_ff(bulge, bulge_min); - - float range = 1.0f - bulge_min; - float scale_fac = (range > 0.0f) ? 1.0f / range : 0.0f; - float soft = 1.0f - range * atanf((1.0f - bulge) * scale_fac) / (float)M_PI_2; - - bulge = interpf(soft, hard, data->bulge_smooth); - } - } - - switch (data->volmode) { - /* volume preserving scaling */ - case VOLUME_XZ: - scale[0] = sqrtf(bulge); - scale[2] = scale[0]; - break; - case VOLUME_X: - scale[0] = bulge; - scale[2] = 1.0; - break; - case VOLUME_Z: - scale[0] = 1.0; - scale[2] = bulge; - break; - /* don't care for volume */ - case NO_VOLUME: - scale[0] = 1.0; - scale[2] = 1.0; - break; - default: /* should not happen, but in case*/ - return; - } /* switch (data->volmode) */ - - /* Clear the object's rotation and scale */ - cob->matrix[0][0] = size[0] * scale[0]; - cob->matrix[0][1] = 0; - cob->matrix[0][2] = 0; - cob->matrix[1][0] = 0; - cob->matrix[1][1] = size[1] * scale[1]; - cob->matrix[1][2] = 0; - cob->matrix[2][0] = 0; - cob->matrix[2][1] = 0; - cob->matrix[2][2] = size[2] * scale[2]; - - sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]); - normalize_v3(vec); - - /* new Y aligns object target connection*/ - negate_v3_v3(totmat[1], vec); - switch (data->plane) { - case PLANE_X: - /* build new Z vector */ - /* othogonal to "new Y" "old X! plane */ - cross_v3_v3v3(orth, vec, xx); - normalize_v3(orth); - - /* new Z*/ - copy_v3_v3(totmat[2], orth); - - /* we decided to keep X plane*/ - cross_v3_v3v3(xx, orth, vec); - normalize_v3_v3(totmat[0], xx); - break; - case PLANE_Z: - /* build new X vector */ - /* othogonal to "new Y" "old Z! plane */ - cross_v3_v3v3(orth, vec, zz); - normalize_v3(orth); - - /* new X */ - negate_v3_v3(totmat[0], orth); - - /* we decided to keep Z */ - cross_v3_v3v3(zz, orth, vec); - normalize_v3_v3(totmat[2], zz); - break; - } /* switch (data->plane) */ - - mul_m4_m3m4(cob->matrix, totmat, cob->matrix); - } + dist = len_v3v3(cob->matrix[3], ct->matrix[3]); + /* Only Y constrained object axis scale should be used, to keep same length when scaling it. */ + dist /= size[1]; + + /* data->orglength==0 occurs on first run, and after 'R' button is clicked */ + if (data->orglength == 0) { + data->orglength = dist; + + /* Write the computed length back to the master copy if in COW evaluation. */ + bConstraint *orig_con = constraint_find_original_for_update(cob, con); + + if (orig_con != NULL) { + bStretchToConstraint *orig_data = orig_con->data; + + orig_data->orglength = data->orglength; + } + } + + scale[1] = dist / data->orglength; + + bulge = powf(data->orglength / dist, data->bulge); + + if (bulge > 1.0f) { + if (data->flag & STRETCHTOCON_USE_BULGE_MAX) { + float bulge_max = max_ff(data->bulge_max, 1.0f); + float hard = min_ff(bulge, bulge_max); + + float range = bulge_max - 1.0f; + float scale_fac = (range > 0.0f) ? 1.0f / range : 0.0f; + float soft = 1.0f + range * atanf((bulge - 1.0f) * scale_fac) / (float)M_PI_2; + + bulge = interpf(soft, hard, data->bulge_smooth); + } + } + if (bulge < 1.0f) { + if (data->flag & STRETCHTOCON_USE_BULGE_MIN) { + float bulge_min = CLAMPIS(data->bulge_min, 0.0f, 1.0f); + float hard = max_ff(bulge, bulge_min); + + float range = 1.0f - bulge_min; + float scale_fac = (range > 0.0f) ? 1.0f / range : 0.0f; + float soft = 1.0f - range * atanf((1.0f - bulge) * scale_fac) / (float)M_PI_2; + + bulge = interpf(soft, hard, data->bulge_smooth); + } + } + + switch (data->volmode) { + /* volume preserving scaling */ + case VOLUME_XZ: + scale[0] = sqrtf(bulge); + scale[2] = scale[0]; + break; + case VOLUME_X: + scale[0] = bulge; + scale[2] = 1.0; + break; + case VOLUME_Z: + scale[0] = 1.0; + scale[2] = bulge; + break; + /* don't care for volume */ + case NO_VOLUME: + scale[0] = 1.0; + scale[2] = 1.0; + break; + default: /* should not happen, but in case*/ + return; + } /* switch (data->volmode) */ + + /* Clear the object's rotation and scale */ + cob->matrix[0][0] = size[0] * scale[0]; + cob->matrix[0][1] = 0; + cob->matrix[0][2] = 0; + cob->matrix[1][0] = 0; + cob->matrix[1][1] = size[1] * scale[1]; + cob->matrix[1][2] = 0; + cob->matrix[2][0] = 0; + cob->matrix[2][1] = 0; + cob->matrix[2][2] = size[2] * scale[2]; + + sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]); + normalize_v3(vec); + + /* new Y aligns object target connection*/ + negate_v3_v3(totmat[1], vec); + switch (data->plane) { + case PLANE_X: + /* build new Z vector */ + /* othogonal to "new Y" "old X! plane */ + cross_v3_v3v3(orth, vec, xx); + normalize_v3(orth); + + /* new Z*/ + copy_v3_v3(totmat[2], orth); + + /* we decided to keep X plane*/ + cross_v3_v3v3(xx, orth, vec); + normalize_v3_v3(totmat[0], xx); + break; + case PLANE_Z: + /* build new X vector */ + /* othogonal to "new Y" "old Z! plane */ + cross_v3_v3v3(orth, vec, zz); + normalize_v3(orth); + + /* new X */ + negate_v3_v3(totmat[0], orth); + + /* we decided to keep Z */ + cross_v3_v3v3(zz, orth, vec); + normalize_v3_v3(totmat[2], zz); + break; + } /* switch (data->plane) */ + + mul_m4_m3m4(cob->matrix, totmat, cob->matrix); + } } static bConstraintTypeInfo CTI_STRETCHTO = { - CONSTRAINT_TYPE_STRETCHTO, /* type */ - sizeof(bStretchToConstraint), /* size */ - "Stretch To", /* name */ - "bStretchToConstraint", /* struct name */ - NULL, /* free data */ - stretchto_id_looper, /* id looper */ - NULL, /* copy data */ - stretchto_new_data, /* new data */ - stretchto_get_tars, /* get constraint targets */ - stretchto_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ - stretchto_evaluate, /* evaluate */ + CONSTRAINT_TYPE_STRETCHTO, /* type */ + sizeof(bStretchToConstraint), /* size */ + "Stretch To", /* name */ + "bStretchToConstraint", /* struct name */ + NULL, /* free data */ + stretchto_id_looper, /* id looper */ + NULL, /* copy data */ + stretchto_new_data, /* new data */ + stretchto_get_tars, /* get constraint targets */ + stretchto_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + stretchto_evaluate, /* evaluate */ }; /* ---------- Floor ------------ */ static void minmax_new_data(void *cdata) { - bMinMaxConstraint *data = (bMinMaxConstraint *)cdata; + bMinMaxConstraint *data = (bMinMaxConstraint *)cdata; - data->minmaxflag = TRACK_Z; - data->offset = 0.0f; - zero_v3(data->cache); - data->flag = 0; + data->minmaxflag = TRACK_Z; + data->offset = 0.0f; + zero_v3(data->cache); + data->flag = 0; } static void minmax_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bMinMaxConstraint *data = con->data; + bMinMaxConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int minmax_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bMinMaxConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bMinMaxConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void minmax_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bMinMaxConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bMinMaxConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } static void minmax_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bMinMaxConstraint *data = con->data; - bConstraintTarget *ct = targets->first; - - /* only evaluate if there is a target */ - if (VALID_CONS_TARGET(ct)) { - float obmat[4][4], imat[4][4], tarmat[4][4], tmat[4][4]; - float val1, val2; - int index; - - copy_m4_m4(obmat, cob->matrix); - copy_m4_m4(tarmat, ct->matrix); - - if (data->flag & MINMAX_USEROT) { - /* take rotation of target into account by doing the transaction in target's localspace */ - invert_m4_m4(imat, tarmat); - mul_m4_m4m4(tmat, imat, obmat); - copy_m4_m4(obmat, tmat); - unit_m4(tarmat); - } - - switch (data->minmaxflag) { - case TRACK_Z: - val1 = tarmat[3][2]; - val2 = obmat[3][2] - data->offset; - index = 2; - break; - case TRACK_Y: - val1 = tarmat[3][1]; - val2 = obmat[3][1] - data->offset; - index = 1; - break; - case TRACK_X: - val1 = tarmat[3][0]; - val2 = obmat[3][0] - data->offset; - index = 0; - break; - case TRACK_nZ: - val2 = tarmat[3][2]; - val1 = obmat[3][2] - data->offset; - index = 2; - break; - case TRACK_nY: - val2 = tarmat[3][1]; - val1 = obmat[3][1] - data->offset; - index = 1; - break; - case TRACK_nX: - val2 = tarmat[3][0]; - val1 = obmat[3][0] - data->offset; - index = 0; - break; - default: - return; - } - - if (val1 > val2) { - obmat[3][index] = tarmat[3][index] + data->offset; - if (data->flag & MINMAX_STICKY) { - if (data->flag & MINMAX_STUCK) { - copy_v3_v3(obmat[3], data->cache); - } - else { - copy_v3_v3(data->cache, obmat[3]); - data->flag |= MINMAX_STUCK; - } - } - if (data->flag & MINMAX_USEROT) { - /* get out of localspace */ - mul_m4_m4m4(tmat, ct->matrix, obmat); - copy_m4_m4(cob->matrix, tmat); - } - else { - copy_v3_v3(cob->matrix[3], obmat[3]); - } - } - else { - data->flag &= ~MINMAX_STUCK; - } - } + bMinMaxConstraint *data = con->data; + bConstraintTarget *ct = targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float obmat[4][4], imat[4][4], tarmat[4][4], tmat[4][4]; + float val1, val2; + int index; + + copy_m4_m4(obmat, cob->matrix); + copy_m4_m4(tarmat, ct->matrix); + + if (data->flag & MINMAX_USEROT) { + /* take rotation of target into account by doing the transaction in target's localspace */ + invert_m4_m4(imat, tarmat); + mul_m4_m4m4(tmat, imat, obmat); + copy_m4_m4(obmat, tmat); + unit_m4(tarmat); + } + + switch (data->minmaxflag) { + case TRACK_Z: + val1 = tarmat[3][2]; + val2 = obmat[3][2] - data->offset; + index = 2; + break; + case TRACK_Y: + val1 = tarmat[3][1]; + val2 = obmat[3][1] - data->offset; + index = 1; + break; + case TRACK_X: + val1 = tarmat[3][0]; + val2 = obmat[3][0] - data->offset; + index = 0; + break; + case TRACK_nZ: + val2 = tarmat[3][2]; + val1 = obmat[3][2] - data->offset; + index = 2; + break; + case TRACK_nY: + val2 = tarmat[3][1]; + val1 = obmat[3][1] - data->offset; + index = 1; + break; + case TRACK_nX: + val2 = tarmat[3][0]; + val1 = obmat[3][0] - data->offset; + index = 0; + break; + default: + return; + } + + if (val1 > val2) { + obmat[3][index] = tarmat[3][index] + data->offset; + if (data->flag & MINMAX_STICKY) { + if (data->flag & MINMAX_STUCK) { + copy_v3_v3(obmat[3], data->cache); + } + else { + copy_v3_v3(data->cache, obmat[3]); + data->flag |= MINMAX_STUCK; + } + } + if (data->flag & MINMAX_USEROT) { + /* get out of localspace */ + mul_m4_m4m4(tmat, ct->matrix, obmat); + copy_m4_m4(cob->matrix, tmat); + } + else { + copy_v3_v3(cob->matrix[3], obmat[3]); + } + } + else { + data->flag &= ~MINMAX_STUCK; + } + } } static bConstraintTypeInfo CTI_MINMAX = { - CONSTRAINT_TYPE_MINMAX, /* type */ - sizeof(bMinMaxConstraint), /* size */ - "Floor", /* name */ - "bMinMaxConstraint", /* struct name */ - NULL, /* free data */ - minmax_id_looper, /* id looper */ - NULL, /* copy data */ - minmax_new_data, /* new data */ - minmax_get_tars, /* get constraint targets */ - minmax_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ - minmax_evaluate, /* evaluate */ + CONSTRAINT_TYPE_MINMAX, /* type */ + sizeof(bMinMaxConstraint), /* size */ + "Floor", /* name */ + "bMinMaxConstraint", /* struct name */ + NULL, /* free data */ + minmax_id_looper, /* id looper */ + NULL, /* copy data */ + minmax_new_data, /* new data */ + minmax_get_tars, /* get constraint targets */ + minmax_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + minmax_evaluate, /* evaluate */ }; /* -------- Clamp To ---------- */ static void clampto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bClampToConstraint *data = con->data; + bClampToConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int clampto_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bClampToConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bClampToConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints without subtargets */ - SINGLETARGETNS_GET_TARS(con, data->tar, ct, list); + /* standard target-getting macro for single-target constraints without subtargets */ + SINGLETARGETNS_GET_TARS(con, data->tar, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void clampto_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bClampToConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bClampToConstraint *data = con->data; + bConstraintTarget *ct = list->first; - /* the following macro is used for all standard single-target constraints */ - SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy); + } } static void clampto_get_tarmat(struct Depsgraph *UNUSED(depsgraph), - bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob), - bConstraintTarget *ct, float UNUSED(ctime)) + bConstraint *UNUSED(con), + bConstraintOb *UNUSED(cob), + bConstraintTarget *ct, + float UNUSED(ctime)) { - /* technically, this isn't really needed for evaluation, but we don't know what else - * might end up calling this... - */ - if (ct) - unit_m4(ct->matrix); + /* technically, this isn't really needed for evaluation, but we don't know what else + * might end up calling this... + */ + if (ct) + unit_m4(ct->matrix); } static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bClampToConstraint *data = con->data; - bConstraintTarget *ct = targets->first; - - /* only evaluate if there is a target and it is a curve */ - if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) { - float obmat[4][4], ownLoc[3]; - float curveMin[3], curveMax[3]; - float targetMatrix[4][4]; - - copy_m4_m4(obmat, cob->matrix); - copy_v3_v3(ownLoc, obmat[3]); - - unit_m4(targetMatrix); - INIT_MINMAX(curveMin, curveMax); - /* XXX - don't think this is good calling this here - campbell */ - BKE_object_minmax(ct->tar, curveMin, curveMax, true); - - /* get targetmatrix */ - if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->path && data->tar->runtime.curve_cache->path->data) { - float vec[4], dir[3], totmat[4][4]; - float curvetime; - short clamp_axis; - - /* find best position on curve */ - /* 1. determine which axis to sample on? */ - if (data->flag == CLAMPTO_AUTO) { - float size[3]; - sub_v3_v3v3(size, curveMax, curveMin); - - /* find axis along which the bounding box has the greatest - * extent. Otherwise, default to the x-axis, as that is quite - * frequently used. - */ - if ((size[2] > size[0]) && (size[2] > size[1])) - clamp_axis = CLAMPTO_Z - 1; - else if ((size[1] > size[0]) && (size[1] > size[2])) - clamp_axis = CLAMPTO_Y - 1; - else - clamp_axis = CLAMPTO_X - 1; - } - else - clamp_axis = data->flag - 1; - - /* 2. determine position relative to curve on a 0-1 scale based on bounding box */ - if (data->flag2 & CLAMPTO_CYCLIC) { - /* cyclic, so offset within relative bounding box is used */ - float len = (curveMax[clamp_axis] - curveMin[clamp_axis]); - float offset; - - /* check to make sure len is not so close to zero that it'll cause errors */ - if (IS_EQF(len, 0.0f) == false) { - /* find bounding-box range where target is located */ - if (ownLoc[clamp_axis] < curveMin[clamp_axis]) { - /* bounding-box range is before */ - offset = curveMin[clamp_axis] - ceilf((curveMin[clamp_axis] - ownLoc[clamp_axis]) / len) * len; - - /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */ - curvetime = (ownLoc[clamp_axis] - offset) / (len); - } - else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) { - /* bounding-box range is after */ - offset = curveMax[clamp_axis] + (int)((ownLoc[clamp_axis] - curveMax[clamp_axis]) / len) * len; - - /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */ - curvetime = (ownLoc[clamp_axis] - offset) / (len); - } - else { - /* as the location falls within bounds, just calculate */ - curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len); - } - } - else { - /* as length is close to zero, curvetime by default should be 0 (i.e. the start) */ - curvetime = 0.0f; - } - } - else { - /* no cyclic, so position is clamped to within the bounding box */ - if (ownLoc[clamp_axis] <= curveMin[clamp_axis]) - curvetime = 0.0f; - else if (ownLoc[clamp_axis] >= curveMax[clamp_axis]) - curvetime = 1.0f; - else if (IS_EQF((curveMax[clamp_axis] - curveMin[clamp_axis]), 0.0f) == false) - curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]); - else - curvetime = 0.0f; - } - - /* 3. position on curve */ - if (where_on_path(ct->tar, curvetime, vec, dir, NULL, NULL, NULL) ) { - unit_m4(totmat); - copy_v3_v3(totmat[3], vec); - - mul_m4_m4m4(targetMatrix, ct->tar->obmat, totmat); - } - } - - /* obtain final object position */ - copy_v3_v3(cob->matrix[3], targetMatrix[3]); - } + bClampToConstraint *data = con->data; + bConstraintTarget *ct = targets->first; + + /* only evaluate if there is a target and it is a curve */ + if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) { + float obmat[4][4], ownLoc[3]; + float curveMin[3], curveMax[3]; + float targetMatrix[4][4]; + + copy_m4_m4(obmat, cob->matrix); + copy_v3_v3(ownLoc, obmat[3]); + + unit_m4(targetMatrix); + INIT_MINMAX(curveMin, curveMax); + /* XXX - don't think this is good calling this here - campbell */ + BKE_object_minmax(ct->tar, curveMin, curveMax, true); + + /* get targetmatrix */ + if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->path && + data->tar->runtime.curve_cache->path->data) { + float vec[4], dir[3], totmat[4][4]; + float curvetime; + short clamp_axis; + + /* find best position on curve */ + /* 1. determine which axis to sample on? */ + if (data->flag == CLAMPTO_AUTO) { + float size[3]; + sub_v3_v3v3(size, curveMax, curveMin); + + /* find axis along which the bounding box has the greatest + * extent. Otherwise, default to the x-axis, as that is quite + * frequently used. + */ + if ((size[2] > size[0]) && (size[2] > size[1])) + clamp_axis = CLAMPTO_Z - 1; + else if ((size[1] > size[0]) && (size[1] > size[2])) + clamp_axis = CLAMPTO_Y - 1; + else + clamp_axis = CLAMPTO_X - 1; + } + else + clamp_axis = data->flag - 1; + + /* 2. determine position relative to curve on a 0-1 scale based on bounding box */ + if (data->flag2 & CLAMPTO_CYCLIC) { + /* cyclic, so offset within relative bounding box is used */ + float len = (curveMax[clamp_axis] - curveMin[clamp_axis]); + float offset; + + /* check to make sure len is not so close to zero that it'll cause errors */ + if (IS_EQF(len, 0.0f) == false) { + /* find bounding-box range where target is located */ + if (ownLoc[clamp_axis] < curveMin[clamp_axis]) { + /* bounding-box range is before */ + offset = curveMin[clamp_axis] - + ceilf((curveMin[clamp_axis] - ownLoc[clamp_axis]) / len) * len; + + /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */ + curvetime = (ownLoc[clamp_axis] - offset) / (len); + } + else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) { + /* bounding-box range is after */ + offset = curveMax[clamp_axis] + + (int)((ownLoc[clamp_axis] - curveMax[clamp_axis]) / len) * len; + + /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */ + curvetime = (ownLoc[clamp_axis] - offset) / (len); + } + else { + /* as the location falls within bounds, just calculate */ + curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len); + } + } + else { + /* as length is close to zero, curvetime by default should be 0 (i.e. the start) */ + curvetime = 0.0f; + } + } + else { + /* no cyclic, so position is clamped to within the bounding box */ + if (ownLoc[clamp_axis] <= curveMin[clamp_axis]) + curvetime = 0.0f; + else if (ownLoc[clamp_axis] >= curveMax[clamp_axis]) + curvetime = 1.0f; + else if (IS_EQF((curveMax[clamp_axis] - curveMin[clamp_axis]), 0.0f) == false) + curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / + (curveMax[clamp_axis] - curveMin[clamp_axis]); + else + curvetime = 0.0f; + } + + /* 3. position on curve */ + if (where_on_path(ct->tar, curvetime, vec, dir, NULL, NULL, NULL)) { + unit_m4(totmat); + copy_v3_v3(totmat[3], vec); + + mul_m4_m4m4(targetMatrix, ct->tar->obmat, totmat); + } + } + + /* obtain final object position */ + copy_v3_v3(cob->matrix[3], targetMatrix[3]); + } } static bConstraintTypeInfo CTI_CLAMPTO = { - CONSTRAINT_TYPE_CLAMPTO, /* type */ - sizeof(bClampToConstraint), /* size */ - "Clamp To", /* name */ - "bClampToConstraint", /* struct name */ - NULL, /* free data */ - clampto_id_looper, /* id looper */ - NULL, /* copy data */ - NULL, /* new data */ - clampto_get_tars, /* get constraint targets */ - clampto_flush_tars, /* flush constraint targets */ - clampto_get_tarmat, /* get target matrix */ - clampto_evaluate, /* evaluate */ + CONSTRAINT_TYPE_CLAMPTO, /* type */ + sizeof(bClampToConstraint), /* size */ + "Clamp To", /* name */ + "bClampToConstraint", /* struct name */ + NULL, /* free data */ + clampto_id_looper, /* id looper */ + NULL, /* copy data */ + NULL, /* new data */ + clampto_get_tars, /* get constraint targets */ + clampto_flush_tars, /* flush constraint targets */ + clampto_get_tarmat, /* get target matrix */ + clampto_evaluate, /* evaluate */ }; /* ---------- Transform Constraint ----------- */ static void transform_new_data(void *cdata) { - bTransformConstraint *data = (bTransformConstraint *)cdata; + bTransformConstraint *data = (bTransformConstraint *)cdata; - data->map[0] = 0; - data->map[1] = 1; - data->map[2] = 2; + data->map[0] = 0; + data->map[1] = 1; + data->map[2] = 2; } static void transform_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bTransformConstraint *data = con->data; + bTransformConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int transform_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bTransformConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bTransformConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void transform_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bTransformConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bTransformConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bTransformConstraint *data = con->data; - bConstraintTarget *ct = targets->first; - - /* only evaluate if there is a target */ - if (VALID_CONS_TARGET(ct)) { - float *from_min, *from_max, *to_min, *to_max; - float loc[3], eul[3], size[3]; - float dvec[3], sval[3]; - int i; - - /* obtain target effect */ - switch (data->from) { - case TRANS_SCALE: - mat4_to_size(dvec, ct->matrix); - - if (is_negative_m4(ct->matrix)) { - /* Bugfix [#27886] - * We can't be sure which axis/axes are negative, though we know that something is negative. - * Assume we don't care about negativity of separate axes. <--- This is a limitation that - * riggers will have to live with for now. - */ - negate_v3(dvec); - } - from_min = data->from_min_scale; - from_max = data->from_max_scale; - break; - case TRANS_ROTATION: - mat4_to_eulO(dvec, cob->rotOrder, ct->matrix); - from_min = data->from_min_rot; - from_max = data->from_max_rot; - break; - case TRANS_LOCATION: - default: - copy_v3_v3(dvec, ct->matrix[3]); - from_min = data->from_min; - from_max = data->from_max; - break; - } - - /* extract components of owner's matrix */ - copy_v3_v3(loc, cob->matrix[3]); - mat4_to_eulO(eul, cob->rotOrder, cob->matrix); - mat4_to_size(size, cob->matrix); - - /* determine where in range current transforms lie */ - if (data->expo) { - for (i = 0; i < 3; i++) { - if (from_max[i] - from_min[i]) - sval[i] = (dvec[i] - from_min[i]) / (from_max[i] - from_min[i]); - else - sval[i] = 0.0f; - } - } - else { - /* clamp transforms out of range */ - for (i = 0; i < 3; i++) { - CLAMP(dvec[i], from_min[i], from_max[i]); - if (from_max[i] - from_min[i]) - sval[i] = (dvec[i] - from_min[i]) / (from_max[i] - from_min[i]); - else - sval[i] = 0.0f; - } - } - - - /* apply transforms */ - switch (data->to) { - case TRANS_SCALE: - to_min = data->to_min_scale; - to_max = data->to_max_scale; - for (i = 0; i < 3; i++) { - /* multiply with original scale (so that it can still be scaled) */ - /* size[i] *= to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); */ - /* Stay absolute, else it breaks existing rigs... sigh. */ - size[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); - } - break; - case TRANS_ROTATION: - to_min = data->to_min_rot; - to_max = data->to_max_rot; - for (i = 0; i < 3; i++) { - /* add to original rotation (so that it can still be rotated) */ - eul[i] += to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); - } - break; - case TRANS_LOCATION: - default: - to_min = data->to_min; - to_max = data->to_max; - for (i = 0; i < 3; i++) { - /* add to original location (so that it can still be moved) */ - loc[i] += (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]))); - } - break; - } - - /* apply to matrix */ - loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder); - } + bTransformConstraint *data = con->data; + bConstraintTarget *ct = targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float *from_min, *from_max, *to_min, *to_max; + float loc[3], eul[3], size[3]; + float dvec[3], sval[3]; + int i; + + /* obtain target effect */ + switch (data->from) { + case TRANS_SCALE: + mat4_to_size(dvec, ct->matrix); + + if (is_negative_m4(ct->matrix)) { + /* Bugfix [#27886] + * We can't be sure which axis/axes are negative, though we know that something is negative. + * Assume we don't care about negativity of separate axes. <--- This is a limitation that + * riggers will have to live with for now. + */ + negate_v3(dvec); + } + from_min = data->from_min_scale; + from_max = data->from_max_scale; + break; + case TRANS_ROTATION: + mat4_to_eulO(dvec, cob->rotOrder, ct->matrix); + from_min = data->from_min_rot; + from_max = data->from_max_rot; + break; + case TRANS_LOCATION: + default: + copy_v3_v3(dvec, ct->matrix[3]); + from_min = data->from_min; + from_max = data->from_max; + break; + } + + /* extract components of owner's matrix */ + copy_v3_v3(loc, cob->matrix[3]); + mat4_to_eulO(eul, cob->rotOrder, cob->matrix); + mat4_to_size(size, cob->matrix); + + /* determine where in range current transforms lie */ + if (data->expo) { + for (i = 0; i < 3; i++) { + if (from_max[i] - from_min[i]) + sval[i] = (dvec[i] - from_min[i]) / (from_max[i] - from_min[i]); + else + sval[i] = 0.0f; + } + } + else { + /* clamp transforms out of range */ + for (i = 0; i < 3; i++) { + CLAMP(dvec[i], from_min[i], from_max[i]); + if (from_max[i] - from_min[i]) + sval[i] = (dvec[i] - from_min[i]) / (from_max[i] - from_min[i]); + else + sval[i] = 0.0f; + } + } + + /* apply transforms */ + switch (data->to) { + case TRANS_SCALE: + to_min = data->to_min_scale; + to_max = data->to_max_scale; + for (i = 0; i < 3; i++) { + /* multiply with original scale (so that it can still be scaled) */ + /* size[i] *= to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); */ + /* Stay absolute, else it breaks existing rigs... sigh. */ + size[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); + } + break; + case TRANS_ROTATION: + to_min = data->to_min_rot; + to_max = data->to_max_rot; + for (i = 0; i < 3; i++) { + /* add to original rotation (so that it can still be rotated) */ + eul[i] += to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); + } + break; + case TRANS_LOCATION: + default: + to_min = data->to_min; + to_max = data->to_max; + for (i = 0; i < 3; i++) { + /* add to original location (so that it can still be moved) */ + loc[i] += (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]))); + } + break; + } + + /* apply to matrix */ + loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder); + } } static bConstraintTypeInfo CTI_TRANSFORM = { - CONSTRAINT_TYPE_TRANSFORM, /* type */ - sizeof(bTransformConstraint), /* size */ - "Transformation", /* name */ - "bTransformConstraint", /* struct name */ - NULL, /* free data */ - transform_id_looper, /* id looper */ - NULL, /* copy data */ - transform_new_data, /* new data */ - transform_get_tars, /* get constraint targets */ - transform_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get a target matrix */ - transform_evaluate, /* evaluate */ + CONSTRAINT_TYPE_TRANSFORM, /* type */ + sizeof(bTransformConstraint), /* size */ + "Transformation", /* name */ + "bTransformConstraint", /* struct name */ + NULL, /* free data */ + transform_id_looper, /* id looper */ + NULL, /* copy data */ + transform_new_data, /* new data */ + transform_get_tars, /* get constraint targets */ + transform_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get a target matrix */ + transform_evaluate, /* evaluate */ }; /* ---------- Shrinkwrap Constraint ----------- */ static void shrinkwrap_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bShrinkwrapConstraint *data = con->data; + bShrinkwrapConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->target, false, userdata); + /* target only */ + func(con, (ID **)&data->target, false, userdata); } static void shrinkwrap_new_data(void *cdata) { - bShrinkwrapConstraint *data = (bShrinkwrapConstraint *)cdata; + bShrinkwrapConstraint *data = (bShrinkwrapConstraint *)cdata; - data->projAxis = OB_POSZ; - data->projAxisSpace = CONSTRAINT_SPACE_LOCAL; + data->projAxis = OB_POSZ; + data->projAxisSpace = CONSTRAINT_SPACE_LOCAL; } static int shrinkwrap_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bShrinkwrapConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bShrinkwrapConstraint *data = con->data; + bConstraintTarget *ct; - SINGLETARGETNS_GET_TARS(con, data->target, ct, list); + SINGLETARGETNS_GET_TARS(con, data->target, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } - static void shrinkwrap_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bShrinkwrapConstraint *data = con->data; - bConstraintTarget *ct = list->first; - - SINGLETARGETNS_FLUSH_TARS(con, data->target, ct, list, no_copy); - } -} - - -static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) -{ - bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data; - - if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) { - - bool fail = false; - float co[3] = {0.0f, 0.0f, 0.0f}; - bool track_normal = false; - float track_no[3] = {0.0f, 0.0f, 0.0f}; - - SpaceTransform transform; - Mesh *target_eval = ct->tar->runtime.mesh_eval; - - copy_m4_m4(ct->matrix, cob->matrix); - - bool do_track_normal = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0; - ShrinkwrapTreeData tree; - - if (BKE_shrinkwrap_init_tree(&tree, target_eval, scon->shrinkType, scon->shrinkMode, do_track_normal)) { - BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat); - - switch (scon->shrinkType) { - case MOD_SHRINKWRAP_NEAREST_SURFACE: - case MOD_SHRINKWRAP_NEAREST_VERTEX: - case MOD_SHRINKWRAP_TARGET_PROJECT: - { - BVHTreeNearest nearest; - - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - - BLI_space_transform_apply(&transform, co); - - BKE_shrinkwrap_find_nearest_surface(&tree, &nearest, co, scon->shrinkType); - - if (nearest.index < 0) { - fail = true; - break; - } - - if (scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) { - if (do_track_normal) { - track_normal = true; - BKE_shrinkwrap_compute_smooth_normal(&tree, NULL, nearest.index, nearest.co, nearest.no, track_no); - BLI_space_transform_invert_normal(&transform, track_no); - } - - BKE_shrinkwrap_snap_point_to_surface(&tree, NULL, scon->shrinkMode, nearest.index, nearest.co, nearest.no, scon->dist, co, co); - } - else { - const float dist = len_v3v3(co, nearest.co); - - if (dist != 0.0f) { - interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */ - } - } - - BLI_space_transform_invert(&transform, co); - break; - } - case MOD_SHRINKWRAP_PROJECT: - { - BVHTreeRayHit hit; - - float mat[4][4]; - float no[3] = {0.0f, 0.0f, 0.0f}; - - /* TODO should use FLT_MAX.. but normal projection doenst yet supports it */ - hit.index = -1; - hit.dist = (scon->projLimit == 0.0f) ? BVH_RAYCAST_DIST_MAX : scon->projLimit; - - switch (scon->projAxis) { - case OB_POSX: case OB_POSY: case OB_POSZ: - no[scon->projAxis - OB_POSX] = 1.0f; - break; - case OB_NEGX: case OB_NEGY: case OB_NEGZ: - no[scon->projAxis - OB_NEGX] = -1.0f; - break; - } - - /* transform normal into requested space */ - /* Note that in this specific case, we need to keep scaling in non-parented 'local2world' object - * case, because SpaceTransform also takes it into account when handling normals. See T42447. */ - unit_m4(mat); - BKE_constraint_mat_convertspace(cob->ob, cob->pchan, mat, - CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true); - invert_m4(mat); - mul_mat3_m4_v3(mat, no); - - if (normalize_v3(no) < FLT_EPSILON) { - fail = true; - break; - } - - char cull_mode = scon->flag & CON_SHRINKWRAP_PROJECT_CULL_MASK; - - BKE_shrinkwrap_project_normal(cull_mode, co, no, 0.0f, &transform, &tree, &hit); - - if (scon->flag & CON_SHRINKWRAP_PROJECT_OPPOSITE) { - float inv_no[3]; - negate_v3_v3(inv_no, no); - - if ((scon->flag & CON_SHRINKWRAP_PROJECT_INVERT_CULL) && (cull_mode != 0)) { - cull_mode ^= CON_SHRINKWRAP_PROJECT_CULL_MASK; - } - - BKE_shrinkwrap_project_normal(cull_mode, co, inv_no, 0.0f, &transform, &tree, &hit); - } - - if (hit.index < 0) { - fail = true; - break; - } - - if (do_track_normal) { - track_normal = true; - BKE_shrinkwrap_compute_smooth_normal(&tree, &transform, hit.index, hit.co, hit.no, track_no); - } - - BKE_shrinkwrap_snap_point_to_surface(&tree, &transform, scon->shrinkMode, hit.index, hit.co, hit.no, scon->dist, co, co); - break; - } - } - - BKE_shrinkwrap_free_tree(&tree); - - if (fail == true) { - /* Don't move the point */ - zero_v3(co); - } - - /* co is in local object coordinates, change it to global and update target position */ - mul_m4_v3(cob->matrix, co); - copy_v3_v3(ct->matrix[3], co); - - if (track_normal) { - mul_mat3_m4_v3(cob->matrix, track_no); - damptrack_do_transform(ct->matrix, track_no, scon->trackAxis); - } - } - } + if (con && list) { + bShrinkwrapConstraint *data = con->data; + bConstraintTarget *ct = list->first; + + SINGLETARGETNS_FLUSH_TARS(con, data->target, ct, list, no_copy); + } +} + +static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), + bConstraint *con, + bConstraintOb *cob, + bConstraintTarget *ct, + float UNUSED(ctime)) +{ + bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *)con->data; + + if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH)) { + + bool fail = false; + float co[3] = {0.0f, 0.0f, 0.0f}; + bool track_normal = false; + float track_no[3] = {0.0f, 0.0f, 0.0f}; + + SpaceTransform transform; + Mesh *target_eval = ct->tar->runtime.mesh_eval; + + copy_m4_m4(ct->matrix, cob->matrix); + + bool do_track_normal = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0; + ShrinkwrapTreeData tree; + + if (BKE_shrinkwrap_init_tree( + &tree, target_eval, scon->shrinkType, scon->shrinkMode, do_track_normal)) { + BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat); + + switch (scon->shrinkType) { + case MOD_SHRINKWRAP_NEAREST_SURFACE: + case MOD_SHRINKWRAP_NEAREST_VERTEX: + case MOD_SHRINKWRAP_TARGET_PROJECT: { + BVHTreeNearest nearest; + + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + + BLI_space_transform_apply(&transform, co); + + BKE_shrinkwrap_find_nearest_surface(&tree, &nearest, co, scon->shrinkType); + + if (nearest.index < 0) { + fail = true; + break; + } + + if (scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) { + if (do_track_normal) { + track_normal = true; + BKE_shrinkwrap_compute_smooth_normal( + &tree, NULL, nearest.index, nearest.co, nearest.no, track_no); + BLI_space_transform_invert_normal(&transform, track_no); + } + + BKE_shrinkwrap_snap_point_to_surface(&tree, + NULL, + scon->shrinkMode, + nearest.index, + nearest.co, + nearest.no, + scon->dist, + co, + co); + } + else { + const float dist = len_v3v3(co, nearest.co); + + if (dist != 0.0f) { + interp_v3_v3v3( + co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */ + } + } + + BLI_space_transform_invert(&transform, co); + break; + } + case MOD_SHRINKWRAP_PROJECT: { + BVHTreeRayHit hit; + + float mat[4][4]; + float no[3] = {0.0f, 0.0f, 0.0f}; + + /* TODO should use FLT_MAX.. but normal projection doenst yet supports it */ + hit.index = -1; + hit.dist = (scon->projLimit == 0.0f) ? BVH_RAYCAST_DIST_MAX : scon->projLimit; + + switch (scon->projAxis) { + case OB_POSX: + case OB_POSY: + case OB_POSZ: + no[scon->projAxis - OB_POSX] = 1.0f; + break; + case OB_NEGX: + case OB_NEGY: + case OB_NEGZ: + no[scon->projAxis - OB_NEGX] = -1.0f; + break; + } + + /* transform normal into requested space */ + /* Note that in this specific case, we need to keep scaling in non-parented 'local2world' object + * case, because SpaceTransform also takes it into account when handling normals. See T42447. */ + unit_m4(mat); + BKE_constraint_mat_convertspace( + cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true); + invert_m4(mat); + mul_mat3_m4_v3(mat, no); + + if (normalize_v3(no) < FLT_EPSILON) { + fail = true; + break; + } + + char cull_mode = scon->flag & CON_SHRINKWRAP_PROJECT_CULL_MASK; + + BKE_shrinkwrap_project_normal(cull_mode, co, no, 0.0f, &transform, &tree, &hit); + + if (scon->flag & CON_SHRINKWRAP_PROJECT_OPPOSITE) { + float inv_no[3]; + negate_v3_v3(inv_no, no); + + if ((scon->flag & CON_SHRINKWRAP_PROJECT_INVERT_CULL) && (cull_mode != 0)) { + cull_mode ^= CON_SHRINKWRAP_PROJECT_CULL_MASK; + } + + BKE_shrinkwrap_project_normal(cull_mode, co, inv_no, 0.0f, &transform, &tree, &hit); + } + + if (hit.index < 0) { + fail = true; + break; + } + + if (do_track_normal) { + track_normal = true; + BKE_shrinkwrap_compute_smooth_normal( + &tree, &transform, hit.index, hit.co, hit.no, track_no); + } + + BKE_shrinkwrap_snap_point_to_surface( + &tree, &transform, scon->shrinkMode, hit.index, hit.co, hit.no, scon->dist, co, co); + break; + } + } + + BKE_shrinkwrap_free_tree(&tree); + + if (fail == true) { + /* Don't move the point */ + zero_v3(co); + } + + /* co is in local object coordinates, change it to global and update target position */ + mul_m4_v3(cob->matrix, co); + copy_v3_v3(ct->matrix[3], co); + + if (track_normal) { + mul_mat3_m4_v3(cob->matrix, track_no); + damptrack_do_transform(ct->matrix, track_no, scon->trackAxis); + } + } + } } static void shrinkwrap_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets) { - bConstraintTarget *ct = targets->first; + bConstraintTarget *ct = targets->first; - /* only evaluate if there is a target */ - if (VALID_CONS_TARGET(ct)) { - copy_m4_m4(cob->matrix, ct->matrix); - } + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + copy_m4_m4(cob->matrix, ct->matrix); + } } static bConstraintTypeInfo CTI_SHRINKWRAP = { - CONSTRAINT_TYPE_SHRINKWRAP, /* type */ - sizeof(bShrinkwrapConstraint), /* size */ - "Shrinkwrap", /* name */ - "bShrinkwrapConstraint", /* struct name */ - NULL, /* free data */ - shrinkwrap_id_looper, /* id looper */ - NULL, /* copy data */ - shrinkwrap_new_data, /* new data */ - shrinkwrap_get_tars, /* get constraint targets */ - shrinkwrap_flush_tars, /* flush constraint targets */ - shrinkwrap_get_tarmat, /* get a target matrix */ - shrinkwrap_evaluate, /* evaluate */ + CONSTRAINT_TYPE_SHRINKWRAP, /* type */ + sizeof(bShrinkwrapConstraint), /* size */ + "Shrinkwrap", /* name */ + "bShrinkwrapConstraint", /* struct name */ + NULL, /* free data */ + shrinkwrap_id_looper, /* id looper */ + NULL, /* copy data */ + shrinkwrap_new_data, /* new data */ + shrinkwrap_get_tars, /* get constraint targets */ + shrinkwrap_flush_tars, /* flush constraint targets */ + shrinkwrap_get_tarmat, /* get a target matrix */ + shrinkwrap_evaluate, /* evaluate */ }; /* --------- Damped Track ---------- */ static void damptrack_new_data(void *cdata) { - bDampTrackConstraint *data = (bDampTrackConstraint *)cdata; + bDampTrackConstraint *data = (bDampTrackConstraint *)cdata; - data->trackflag = TRACK_Y; + data->trackflag = TRACK_Y; } static void damptrack_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bDampTrackConstraint *data = con->data; + bDampTrackConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int damptrack_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bDampTrackConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bDampTrackConstraint *data = con->data; + bConstraintTarget *ct; - /* the following macro is used for all standard single-target constraints */ - SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void damptrack_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bDampTrackConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bDampTrackConstraint *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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } /* array of direction vectors for the tracking flags */ static const float track_dir_vecs[6][3] = { - {+1, 0, 0}, {0, +1, 0}, {0, 0, +1}, /* TRACK_X, TRACK_Y, TRACK_Z */ - {-1, 0, 0}, {0, -1, 0}, {0, 0, -1} /* TRACK_NX, TRACK_NY, TRACK_NZ */ + {+1, 0, 0}, + {0, +1, 0}, + {0, 0, +1}, /* TRACK_X, TRACK_Y, TRACK_Z */ + {-1, 0, 0}, + {0, -1, 0}, + {0, 0, -1} /* TRACK_NX, TRACK_NY, TRACK_NZ */ }; static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { - bDampTrackConstraint *data = con->data; - bConstraintTarget *ct = targets->first; + bDampTrackConstraint *data = con->data; + bConstraintTarget *ct = targets->first; - if (VALID_CONS_TARGET(ct)) { - float tarvec[3]; + if (VALID_CONS_TARGET(ct)) { + float tarvec[3]; - /* find the (unit) direction vector going from the owner to the target */ - sub_v3_v3v3(tarvec, ct->matrix[3], cob->matrix[3]); + /* find the (unit) direction vector going from the owner to the target */ + sub_v3_v3v3(tarvec, ct->matrix[3], cob->matrix[3]); - damptrack_do_transform(cob->matrix, tarvec, data->trackflag); - } + damptrack_do_transform(cob->matrix, tarvec, data->trackflag); + } } static void damptrack_do_transform(float matrix[4][4], const float tarvec_in[3], int track_axis) { - /* find the (unit) direction vector going from the owner to the target */ - float tarvec[3]; - - if (normalize_v3_v3(tarvec, tarvec_in) != 0.0f) { - float obvec[3], obloc[3]; - float raxis[3], rangle; - float rmat[3][3], tmat[4][4]; - - /* find the (unit) direction that the axis we're interested in currently points - * - mul_mat3_m4_v3() only takes the 3x3 (rotation+scaling) components of the 4x4 matrix - * - the normalization step at the end should take care of any unwanted scaling - * left over in the 3x3 matrix we used - */ - copy_v3_v3(obvec, track_dir_vecs[track_axis]); - mul_mat3_m4_v3(matrix, obvec); - - if (normalize_v3(obvec) == 0.0f) { - /* exceptional case - just use the track vector as appropriate */ - copy_v3_v3(obvec, track_dir_vecs[track_axis]); - } - - copy_v3_v3(obloc, matrix[3]); - - /* determine the axis-angle rotation, which represents the smallest possible rotation - * between the two rotation vectors (i.e. the 'damping' referred to in the name) - * - we take this to be the rotation around the normal axis/vector to the plane defined - * by the current and destination vectors, which will 'map' the current axis to the - * destination vector - * - the min/max wrappers around (obvec . tarvec) result (stored temporarily in rangle) - * are used to ensure that the smallest angle is chosen - */ - cross_v3_v3v3_hi_prec(raxis, obvec, tarvec); - - rangle = dot_v3v3(obvec, tarvec); - rangle = acosf(max_ff(-1.0f, min_ff(1.0f, rangle))); - - /* construct rotation matrix from the axis-angle rotation found above - * - this call takes care to make sure that the axis provided is a unit vector first - */ - float norm = normalize_v3(raxis); - - if (norm < FLT_EPSILON) { - /* if dot product is nonzero, while cross is zero, we have two opposite vectors! - * - this is an ambiguity in the math that needs to be resolved arbitrarily, - * or there will be a case where damped track strangely does nothing - * - to do that, rotate around a different local axis - */ - float tmpvec[3]; - - if (fabsf(rangle) < M_PI - 0.01f) { - return; - } - - rangle = M_PI; - copy_v3_v3(tmpvec, track_dir_vecs[(track_axis + 1) % 6]); - mul_mat3_m4_v3(matrix, tmpvec); - cross_v3_v3v3(raxis, obvec, tmpvec); - - if (normalize_v3(raxis) == 0.0f) { - return; - } - } - else if (norm < 0.1f) { - /* near 0 and Pi arcsin has way better precision than arccos */ - rangle = (rangle > M_PI_2) ? M_PI - asinf(norm) : asinf(norm); - } - - axis_angle_normalized_to_mat3(rmat, raxis, rangle); - - /* rotate the owner in the way defined by this rotation matrix, then reapply the location since - * we may have destroyed that in the process of multiplying the matrix - */ - unit_m4(tmat); - mul_m4_m3m4(tmat, rmat, matrix); // m1, m3, m2 - - copy_m4_m4(matrix, tmat); - copy_v3_v3(matrix[3], obloc); - } + /* find the (unit) direction vector going from the owner to the target */ + float tarvec[3]; + + if (normalize_v3_v3(tarvec, tarvec_in) != 0.0f) { + float obvec[3], obloc[3]; + float raxis[3], rangle; + float rmat[3][3], tmat[4][4]; + + /* find the (unit) direction that the axis we're interested in currently points + * - mul_mat3_m4_v3() only takes the 3x3 (rotation+scaling) components of the 4x4 matrix + * - the normalization step at the end should take care of any unwanted scaling + * left over in the 3x3 matrix we used + */ + copy_v3_v3(obvec, track_dir_vecs[track_axis]); + mul_mat3_m4_v3(matrix, obvec); + + if (normalize_v3(obvec) == 0.0f) { + /* exceptional case - just use the track vector as appropriate */ + copy_v3_v3(obvec, track_dir_vecs[track_axis]); + } + + copy_v3_v3(obloc, matrix[3]); + + /* determine the axis-angle rotation, which represents the smallest possible rotation + * between the two rotation vectors (i.e. the 'damping' referred to in the name) + * - we take this to be the rotation around the normal axis/vector to the plane defined + * by the current and destination vectors, which will 'map' the current axis to the + * destination vector + * - the min/max wrappers around (obvec . tarvec) result (stored temporarily in rangle) + * are used to ensure that the smallest angle is chosen + */ + cross_v3_v3v3_hi_prec(raxis, obvec, tarvec); + + rangle = dot_v3v3(obvec, tarvec); + rangle = acosf(max_ff(-1.0f, min_ff(1.0f, rangle))); + + /* construct rotation matrix from the axis-angle rotation found above + * - this call takes care to make sure that the axis provided is a unit vector first + */ + float norm = normalize_v3(raxis); + + if (norm < FLT_EPSILON) { + /* if dot product is nonzero, while cross is zero, we have two opposite vectors! + * - this is an ambiguity in the math that needs to be resolved arbitrarily, + * or there will be a case where damped track strangely does nothing + * - to do that, rotate around a different local axis + */ + float tmpvec[3]; + + if (fabsf(rangle) < M_PI - 0.01f) { + return; + } + + rangle = M_PI; + copy_v3_v3(tmpvec, track_dir_vecs[(track_axis + 1) % 6]); + mul_mat3_m4_v3(matrix, tmpvec); + cross_v3_v3v3(raxis, obvec, tmpvec); + + if (normalize_v3(raxis) == 0.0f) { + return; + } + } + else if (norm < 0.1f) { + /* near 0 and Pi arcsin has way better precision than arccos */ + rangle = (rangle > M_PI_2) ? M_PI - asinf(norm) : asinf(norm); + } + + axis_angle_normalized_to_mat3(rmat, raxis, rangle); + + /* rotate the owner in the way defined by this rotation matrix, then reapply the location since + * we may have destroyed that in the process of multiplying the matrix + */ + unit_m4(tmat); + mul_m4_m3m4(tmat, rmat, matrix); // m1, m3, m2 + + copy_m4_m4(matrix, tmat); + copy_v3_v3(matrix[3], obloc); + } } static bConstraintTypeInfo CTI_DAMPTRACK = { - CONSTRAINT_TYPE_DAMPTRACK, /* type */ - sizeof(bDampTrackConstraint), /* size */ - "Damped Track", /* name */ - "bDampTrackConstraint", /* struct name */ - NULL, /* free data */ - damptrack_id_looper, /* id looper */ - NULL, /* copy data */ - damptrack_new_data, /* new data */ - damptrack_get_tars, /* get constraint targets */ - damptrack_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ - damptrack_evaluate, /* evaluate */ + CONSTRAINT_TYPE_DAMPTRACK, /* type */ + sizeof(bDampTrackConstraint), /* size */ + "Damped Track", /* name */ + "bDampTrackConstraint", /* struct name */ + NULL, /* free data */ + damptrack_id_looper, /* id looper */ + NULL, /* copy data */ + damptrack_new_data, /* new data */ + damptrack_get_tars, /* get constraint targets */ + damptrack_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + damptrack_evaluate, /* evaluate */ }; /* ----------- Spline IK ------------ */ static void splineik_free(bConstraint *con) { - bSplineIKConstraint *data = con->data; + bSplineIKConstraint *data = con->data; - /* binding array */ - if (data->points) - MEM_freeN(data->points); + /* binding array */ + if (data->points) + MEM_freeN(data->points); } static void splineik_copy(bConstraint *con, bConstraint *srccon) { - bSplineIKConstraint *src = srccon->data; - bSplineIKConstraint *dst = con->data; + bSplineIKConstraint *src = srccon->data; + bSplineIKConstraint *dst = con->data; - /* copy the binding array */ - dst->points = MEM_dupallocN(src->points); + /* copy the binding array */ + dst->points = MEM_dupallocN(src->points); } static void splineik_new_data(void *cdata) { - bSplineIKConstraint *data = (bSplineIKConstraint *)cdata; + bSplineIKConstraint *data = (bSplineIKConstraint *)cdata; - data->chainlen = 1; - data->bulge = 1.0; - data->bulge_max = 1.0f; - data->bulge_min = 1.0f; + data->chainlen = 1; + data->bulge = 1.0; + data->bulge_max = 1.0f; + data->bulge_min = 1.0f; - data->yScaleMode = CONSTRAINT_SPLINEIK_YS_FIT_CURVE; + data->yScaleMode = CONSTRAINT_SPLINEIK_YS_FIT_CURVE; } static void splineik_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bSplineIKConstraint *data = con->data; + bSplineIKConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int splineik_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bSplineIKConstraint *data = con->data; - bConstraintTarget *ct; + if (con && list) { + bSplineIKConstraint *data = con->data; + bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints without subtargets */ - SINGLETARGETNS_GET_TARS(con, data->tar, ct, list); + /* standard target-getting macro for single-target constraints without subtargets */ + SINGLETARGETNS_GET_TARS(con, data->tar, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void splineik_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bSplineIKConstraint *data = con->data; - bConstraintTarget *ct = list->first; + if (con && list) { + bSplineIKConstraint *data = con->data; + bConstraintTarget *ct = list->first; - /* the following macro is used for all standard single-target constraints */ - SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy); + } } static void splineik_get_tarmat(struct Depsgraph *UNUSED(depsgraph), - bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob), - bConstraintTarget *ct, float UNUSED(ctime)) + bConstraint *UNUSED(con), + bConstraintOb *UNUSED(cob), + bConstraintTarget *ct, + float UNUSED(ctime)) { - /* technically, this isn't really needed for evaluation, but we don't know what else - * might end up calling this... - */ - if (ct) - unit_m4(ct->matrix); + /* technically, this isn't really needed for evaluation, but we don't know what else + * might end up calling this... + */ + if (ct) + unit_m4(ct->matrix); } static bConstraintTypeInfo CTI_SPLINEIK = { - CONSTRAINT_TYPE_SPLINEIK, /* type */ - sizeof(bSplineIKConstraint), /* size */ - "Spline IK", /* name */ - "bSplineIKConstraint", /* struct name */ - splineik_free, /* free data */ - splineik_id_looper, /* id looper */ - splineik_copy, /* copy data */ - splineik_new_data, /* new data */ - splineik_get_tars, /* get constraint targets */ - splineik_flush_tars, /* flush constraint targets */ - splineik_get_tarmat, /* get target matrix */ - NULL, /* evaluate - solved as separate loop */ + CONSTRAINT_TYPE_SPLINEIK, /* type */ + sizeof(bSplineIKConstraint), /* size */ + "Spline IK", /* name */ + "bSplineIKConstraint", /* struct name */ + splineik_free, /* free data */ + splineik_id_looper, /* id looper */ + splineik_copy, /* copy data */ + splineik_new_data, /* new data */ + splineik_get_tars, /* get constraint targets */ + splineik_flush_tars, /* flush constraint targets */ + splineik_get_tarmat, /* get target matrix */ + NULL, /* evaluate - solved as separate loop */ }; /* ----------- Pivot ------------- */ static void pivotcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bPivotConstraint *data = con->data; + bPivotConstraint *data = con->data; - /* target only */ - func(con, (ID **)&data->tar, false, userdata); + /* target only */ + func(con, (ID **)&data->tar, false, userdata); } static int pivotcon_get_tars(bConstraint *con, ListBase *list) { - if (con && list) { - bPivotConstraint *data = con->data; - bConstraintTarget *ct; + 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); + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; - } + return 1; + } - return 0; + return 0; } static void pivotcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy) { - if (con && list) { - bPivotConstraint *data = con->data; - bConstraintTarget *ct = list->first; + 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, no_copy); - } + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + } } 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]; - - /* pivot correction */ - float axis[3], angle; - - /* 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 */ - copy_v3_v3(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); - - - /* correct the pivot by the rotation axis otherwise the pivot translates when it shouldnt */ - mat3_normalized_to_axis_angle(axis, &angle, rotMat); - if (angle) { - float dvec[3]; - sub_v3_v3v3(vec, pivot, cob->matrix[3]); - project_v3_v3v3(dvec, vec, axis); - sub_v3_v3(pivot, dvec); - } - - /* perform the pivoting... */ - /* 1. take the vector from owner to the pivot */ - sub_v3_v3v3(vec, cob->matrix[3], pivot); - /* 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); + bPivotConstraint *data = con->data; + bConstraintTarget *ct = targets->first; + + float pivot[3], vec[3]; + float rotMat[3][3]; + + /* pivot correction */ + float axis[3], angle; + + /* 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 */ + copy_v3_v3(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); + + /* correct the pivot by the rotation axis otherwise the pivot translates when it shouldnt */ + mat3_normalized_to_axis_angle(axis, &angle, rotMat); + if (angle) { + float dvec[3]; + sub_v3_v3v3(vec, pivot, cob->matrix[3]); + project_v3_v3v3(dvec, vec, axis); + sub_v3_v3(pivot, dvec); + } + + /* perform the pivoting... */ + /* 1. take the vector from owner to the pivot */ + sub_v3_v3v3(vec, cob->matrix[3], pivot); + /* 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 */ - pivotcon_id_looper, /* id looper */ - NULL, /* copy data */ - NULL, /* new data */ // XXX: might be needed to get 'normal' pivot behavior... - pivotcon_get_tars, /* get constraint targets */ - pivotcon_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ - pivotcon_evaluate, /* evaluate */ + CONSTRAINT_TYPE_PIVOT, /* type */ + sizeof(bPivotConstraint), /* size */ + "Pivot", /* name */ + "bPivotConstraint", /* struct name */ + NULL, /* free data */ + pivotcon_id_looper, /* id looper */ + NULL, /* copy data */ + NULL, + /* new data */ // XXX: might be needed to get 'normal' pivot behavior... + pivotcon_get_tars, /* get constraint targets */ + pivotcon_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + pivotcon_evaluate, /* evaluate */ }; /* ----------- Follow Track ------------- */ static void followtrack_new_data(void *cdata) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *)cdata; + bFollowTrackConstraint *data = (bFollowTrackConstraint *)cdata; - data->clip = NULL; - data->flag |= FOLLOWTRACK_ACTIVECLIP; + data->clip = NULL; + data->flag |= FOLLOWTRACK_ACTIVECLIP; } static void followtrack_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bFollowTrackConstraint *data = con->data; + bFollowTrackConstraint *data = con->data; - func(con, (ID **)&data->clip, true, userdata); - func(con, (ID **)&data->camera, false, userdata); - func(con, (ID **)&data->depth_ob, false, userdata); + func(con, (ID **)&data->clip, true, userdata); + func(con, (ID **)&data->camera, false, userdata); + func(con, (ID **)&data->depth_ob, false, userdata); } static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) { - Depsgraph *depsgraph = cob->depsgraph; - Scene *scene = cob->scene; - bFollowTrackConstraint *data = con->data; - MovieClip *clip = data->clip; - MovieTracking *tracking; - MovieTrackingTrack *track; - MovieTrackingObject *tracking_object; - - Object *camob_eval = DEG_get_evaluated_object( - depsgraph, - data->camera ? data->camera : scene->camera); + Depsgraph *depsgraph = cob->depsgraph; + Scene *scene = cob->scene; + bFollowTrackConstraint *data = con->data; + MovieClip *clip = data->clip; + MovieTracking *tracking; + MovieTrackingTrack *track; + MovieTrackingObject *tracking_object; - float ctime = DEG_get_ctime(depsgraph); - float framenr; + Object *camob_eval = DEG_get_evaluated_object(depsgraph, + data->camera ? data->camera : scene->camera); - if (data->flag & FOLLOWTRACK_ACTIVECLIP) - clip = scene->clip; + float ctime = DEG_get_ctime(depsgraph); + float framenr; - if (!clip || !data->track[0] || !camob_eval) - return; + if (data->flag & FOLLOWTRACK_ACTIVECLIP) + clip = scene->clip; - tracking = &clip->tracking; + if (!clip || !data->track[0] || !camob_eval) + return; - if (data->object[0]) - tracking_object = BKE_tracking_object_get_named(tracking, data->object); - else - tracking_object = BKE_tracking_object_get_camera(tracking); + tracking = &clip->tracking; - if (!tracking_object) - return; + if (data->object[0]) + tracking_object = BKE_tracking_object_get_named(tracking, data->object); + else + tracking_object = BKE_tracking_object_get_camera(tracking); - track = BKE_tracking_track_get_named(tracking, tracking_object, data->track); + if (!tracking_object) + return; - if (!track) - return; + track = BKE_tracking_track_get_named(tracking, tracking_object, data->track); - framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); + if (!track) + return; - if (data->flag & FOLLOWTRACK_USE_3D_POSITION) { - if (track->flag & TRACK_HAS_BUNDLE) { - float obmat[4][4], mat[4][4]; + framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); - copy_m4_m4(obmat, cob->matrix); + if (data->flag & FOLLOWTRACK_USE_3D_POSITION) { + if (track->flag & TRACK_HAS_BUNDLE) { + float obmat[4][4], mat[4][4]; - if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) { - float imat[4][4]; + copy_m4_m4(obmat, cob->matrix); - copy_m4_m4(mat, camob_eval->obmat); + if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) { + float imat[4][4]; - BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, imat); - invert_m4(imat); + copy_m4_m4(mat, camob_eval->obmat); - mul_m4_series(cob->matrix, obmat, mat, imat); - translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); - } - else { - BKE_tracking_get_camera_object_matrix(cob->scene, camob_eval, mat); + BKE_tracking_camera_get_reconstructed_interpolate( + tracking, tracking_object, framenr, imat); + invert_m4(imat); - mul_m4_m4m4(cob->matrix, obmat, mat); - translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); - } - } - } - else { - float vec[3], disp[3], axis[3], mat[4][4]; - float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp); - float len, d; + mul_m4_series(cob->matrix, obmat, mat, imat); + translate_m4( + cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); + } + else { + BKE_tracking_get_camera_object_matrix(cob->scene, camob_eval, mat); - BKE_object_where_is_calc_mat4(camob_eval, mat); + mul_m4_m4m4(cob->matrix, obmat, mat); + translate_m4( + cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); + } + } + } + else { + float vec[3], disp[3], axis[3], mat[4][4]; + float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp); + float len, d; - /* camera axis */ - vec[0] = 0.0f; - vec[1] = 0.0f; - vec[2] = 1.0f; - mul_v3_m4v3(axis, mat, vec); + BKE_object_where_is_calc_mat4(camob_eval, mat); - /* distance to projection plane */ - copy_v3_v3(vec, cob->matrix[3]); - sub_v3_v3(vec, mat[3]); - project_v3_v3v3(disp, vec, axis); + /* camera axis */ + vec[0] = 0.0f; + vec[1] = 0.0f; + vec[2] = 1.0f; + mul_v3_m4v3(axis, mat, vec); - len = len_v3(disp); + /* distance to projection plane */ + copy_v3_v3(vec, cob->matrix[3]); + sub_v3_v3(vec, mat[3]); + project_v3_v3v3(disp, vec, axis); - if (len > FLT_EPSILON) { - CameraParams params; - int width, height; - float pos[2], rmat[4][4]; + len = len_v3(disp); - BKE_movieclip_get_size(clip, NULL, &width, &height); - BKE_tracking_marker_get_subframe_position(track, framenr, pos); + if (len > FLT_EPSILON) { + CameraParams params; + int width, height; + float pos[2], rmat[4][4]; - if (data->flag & FOLLOWTRACK_USE_UNDISTORTION) { - /* Undistortion need to happen in pixel space. */ - pos[0] *= width; - pos[1] *= height; + BKE_movieclip_get_size(clip, NULL, &width, &height); + BKE_tracking_marker_get_subframe_position(track, framenr, pos); - BKE_tracking_undistort_v2(tracking, pos, pos); + if (data->flag & FOLLOWTRACK_USE_UNDISTORTION) { + /* Undistortion need to happen in pixel space. */ + pos[0] *= width; + pos[1] *= height; - /* Normalize pixel coordinates back. */ - pos[0] /= width; - pos[1] /= height; - } + BKE_tracking_undistort_v2(tracking, pos, pos); - /* aspect correction */ - if (data->frame_method != FOLLOWTRACK_FRAME_STRETCH) { - float w_src, h_src, w_dst, h_dst, asp_src, asp_dst; + /* Normalize pixel coordinates back. */ + pos[0] /= width; + pos[1] /= height; + } - /* apply clip display aspect */ - w_src = width * clip->aspx; - h_src = height * clip->aspy; + /* aspect correction */ + if (data->frame_method != FOLLOWTRACK_FRAME_STRETCH) { + float w_src, h_src, w_dst, h_dst, asp_src, asp_dst; - w_dst = scene->r.xsch * scene->r.xasp; - h_dst = scene->r.ysch * scene->r.yasp; + /* apply clip display aspect */ + w_src = width * clip->aspx; + h_src = height * clip->aspy; - asp_src = w_src / h_src; - asp_dst = w_dst / h_dst; + w_dst = scene->r.xsch * scene->r.xasp; + h_dst = scene->r.ysch * scene->r.yasp; - if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { - if ((asp_src > asp_dst) == (data->frame_method == FOLLOWTRACK_FRAME_CROP)) { - /* fit X */ - float div = asp_src / asp_dst; - float cent = (float) width / 2.0f; + asp_src = w_src / h_src; + asp_dst = w_dst / h_dst; - pos[0] = (((pos[0] * width - cent) * div) + cent) / width; - } - else { - /* fit Y */ - float div = asp_dst / asp_src; - float cent = (float) height / 2.0f; + if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { + if ((asp_src > asp_dst) == (data->frame_method == FOLLOWTRACK_FRAME_CROP)) { + /* fit X */ + float div = asp_src / asp_dst; + float cent = (float)width / 2.0f; - pos[1] = (((pos[1] * height - cent) * div) + cent) / height; - } - } - } + pos[0] = (((pos[0] * width - cent) * div) + cent) / width; + } + else { + /* fit Y */ + float div = asp_dst / asp_src; + float cent = (float)height / 2.0f; - BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, camob_eval); + pos[1] = (((pos[1] * height - cent) * div) + cent) / height; + } + } + } - if (params.is_ortho) { - vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx); - vec[1] = params.ortho_scale * (pos[1] - 0.5f + params.shifty); - vec[2] = -len; + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, camob_eval); - if (aspect > 1.0f) - vec[1] /= aspect; - else - vec[0] *= aspect; + if (params.is_ortho) { + vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx); + vec[1] = params.ortho_scale * (pos[1] - 0.5f + params.shifty); + vec[2] = -len; + + if (aspect > 1.0f) + vec[1] /= aspect; + else + vec[0] *= aspect; + + mul_v3_m4v3(disp, camob_eval->obmat, vec); + + copy_m4_m4(rmat, camob_eval->obmat); + zero_v3(rmat[3]); + mul_m4_m4m4(cob->matrix, cob->matrix, rmat); + + copy_v3_v3(cob->matrix[3], disp); + } + else { + d = (len * params.sensor_x) / (2.0f * params.lens); + + vec[0] = d * (2.0f * (pos[0] + params.shiftx) - 1.0f); + vec[1] = d * (2.0f * (pos[1] + params.shifty) - 1.0f); + vec[2] = -len; - mul_v3_m4v3(disp, camob_eval->obmat, vec); - - copy_m4_m4(rmat, camob_eval->obmat); - zero_v3(rmat[3]); - mul_m4_m4m4(cob->matrix, cob->matrix, rmat); - - copy_v3_v3(cob->matrix[3], disp); - } - else { - d = (len * params.sensor_x) / (2.0f * params.lens); - - vec[0] = d * (2.0f * (pos[0] + params.shiftx) - 1.0f); - vec[1] = d * (2.0f * (pos[1] + params.shifty) - 1.0f); - vec[2] = -len; + if (aspect > 1.0f) + vec[1] /= aspect; + else + vec[0] *= aspect; - if (aspect > 1.0f) - vec[1] /= aspect; - else - vec[0] *= aspect; + mul_v3_m4v3(disp, camob_eval->obmat, vec); - mul_v3_m4v3(disp, camob_eval->obmat, vec); + /* apply camera rotation so Z-axis would be co-linear */ + copy_m4_m4(rmat, camob_eval->obmat); + zero_v3(rmat[3]); + mul_m4_m4m4(cob->matrix, cob->matrix, rmat); - /* apply camera rotation so Z-axis would be co-linear */ - copy_m4_m4(rmat, camob_eval->obmat); - zero_v3(rmat[3]); - mul_m4_m4m4(cob->matrix, cob->matrix, rmat); + copy_v3_v3(cob->matrix[3], disp); + } - copy_v3_v3(cob->matrix[3], disp); - } + if (data->depth_ob) { + Object *depth_ob = data->depth_ob; + Mesh *target_eval = depth_ob->runtime.mesh_eval; + if (target_eval) { + BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; + BVHTreeRayHit hit; + float ray_start[3], ray_end[3], ray_nor[3], imat[4][4]; + int result; - if (data->depth_ob) { - Object *depth_ob = data->depth_ob; - Mesh *target_eval = depth_ob->runtime.mesh_eval; - if (target_eval) { - BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; - BVHTreeRayHit hit; - float ray_start[3], ray_end[3], ray_nor[3], imat[4][4]; - int result; + invert_m4_m4(imat, depth_ob->obmat); - invert_m4_m4(imat, depth_ob->obmat); + mul_v3_m4v3(ray_start, imat, camob_eval->obmat[3]); + mul_v3_m4v3(ray_end, imat, cob->matrix[3]); - mul_v3_m4v3(ray_start, imat, camob_eval->obmat[3]); - mul_v3_m4v3(ray_end, imat, cob->matrix[3]); + sub_v3_v3v3(ray_nor, ray_end, ray_start); + normalize_v3(ray_nor); - sub_v3_v3v3(ray_nor, ray_end, ray_start); - normalize_v3(ray_nor); + BKE_bvhtree_from_mesh_get(&treeData, target_eval, BVHTREE_FROM_LOOPTRI, 4); - BKE_bvhtree_from_mesh_get(&treeData, target_eval, BVHTREE_FROM_LOOPTRI, 4); + hit.dist = BVH_RAYCAST_DIST_MAX; + hit.index = -1; - hit.dist = BVH_RAYCAST_DIST_MAX; - hit.index = -1; + result = BLI_bvhtree_ray_cast( + treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData); - result = BLI_bvhtree_ray_cast( - treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData); + if (result != -1) { + mul_v3_m4v3(cob->matrix[3], depth_ob->obmat, hit.co); + } - if (result != -1) { - mul_v3_m4v3(cob->matrix[3], depth_ob->obmat, hit.co); - } - - free_bvhtree_from_mesh(&treeData); - } - } - } - } + free_bvhtree_from_mesh(&treeData); + } + } + } + } } static bConstraintTypeInfo CTI_FOLLOWTRACK = { - CONSTRAINT_TYPE_FOLLOWTRACK, /* type */ - sizeof(bFollowTrackConstraint), /* size */ - "Follow Track", /* name */ - "bFollowTrackConstraint", /* struct name */ - NULL, /* free data */ - followtrack_id_looper, /* id looper */ - NULL, /* copy data */ - followtrack_new_data, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ - NULL, /* get target matrix */ - followtrack_evaluate, /* evaluate */ + CONSTRAINT_TYPE_FOLLOWTRACK, /* type */ + sizeof(bFollowTrackConstraint), /* size */ + "Follow Track", /* name */ + "bFollowTrackConstraint", /* struct name */ + NULL, /* free data */ + followtrack_id_looper, /* id looper */ + NULL, /* copy data */ + followtrack_new_data, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + followtrack_evaluate, /* evaluate */ }; /* ----------- Camre Solver ------------- */ static void camerasolver_new_data(void *cdata) { - bCameraSolverConstraint *data = (bCameraSolverConstraint *)cdata; + bCameraSolverConstraint *data = (bCameraSolverConstraint *)cdata; - data->clip = NULL; - data->flag |= CAMERASOLVER_ACTIVECLIP; + data->clip = NULL; + data->flag |= CAMERASOLVER_ACTIVECLIP; } static void camerasolver_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bCameraSolverConstraint *data = con->data; + bCameraSolverConstraint *data = con->data; - func(con, (ID **)&data->clip, true, userdata); + func(con, (ID **)&data->clip, true, userdata); } static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) { - Depsgraph *depsgraph = cob->depsgraph; - Scene *scene = cob->scene; - bCameraSolverConstraint *data = con->data; - MovieClip *clip = data->clip; + Depsgraph *depsgraph = cob->depsgraph; + Scene *scene = cob->scene; + bCameraSolverConstraint *data = con->data; + MovieClip *clip = data->clip; - if (data->flag & CAMERASOLVER_ACTIVECLIP) - clip = scene->clip; + if (data->flag & CAMERASOLVER_ACTIVECLIP) + clip = scene->clip; - if (clip) { - float mat[4][4], obmat[4][4]; - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object = BKE_tracking_object_get_camera(tracking); - float ctime = DEG_get_ctime(depsgraph); - float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); + if (clip) { + float mat[4][4], obmat[4][4]; + MovieTracking *tracking = &clip->tracking; + MovieTrackingObject *object = BKE_tracking_object_get_camera(tracking); + float ctime = DEG_get_ctime(depsgraph); + float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); - BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat); + BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat); - copy_m4_m4(obmat, cob->matrix); + copy_m4_m4(obmat, cob->matrix); - mul_m4_m4m4(cob->matrix, obmat, mat); - } + mul_m4_m4m4(cob->matrix, obmat, mat); + } } static bConstraintTypeInfo CTI_CAMERASOLVER = { - CONSTRAINT_TYPE_CAMERASOLVER, /* type */ - sizeof(bCameraSolverConstraint), /* size */ - "Camera Solver", /* name */ - "bCameraSolverConstraint", /* struct name */ - NULL, /* free data */ - camerasolver_id_looper, /* id looper */ - NULL, /* copy data */ - camerasolver_new_data, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ - NULL, /* get target matrix */ - camerasolver_evaluate, /* evaluate */ + CONSTRAINT_TYPE_CAMERASOLVER, /* type */ + sizeof(bCameraSolverConstraint), /* size */ + "Camera Solver", /* name */ + "bCameraSolverConstraint", /* struct name */ + NULL, /* free data */ + camerasolver_id_looper, /* id looper */ + NULL, /* copy data */ + camerasolver_new_data, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + camerasolver_evaluate, /* evaluate */ }; /* ----------- Object Solver ------------- */ static void objectsolver_new_data(void *cdata) { - bObjectSolverConstraint *data = (bObjectSolverConstraint *)cdata; + bObjectSolverConstraint *data = (bObjectSolverConstraint *)cdata; - data->clip = NULL; - data->flag |= OBJECTSOLVER_ACTIVECLIP; - unit_m4(data->invmat); + data->clip = NULL; + data->flag |= OBJECTSOLVER_ACTIVECLIP; + unit_m4(data->invmat); } static void objectsolver_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bObjectSolverConstraint *data = con->data; + bObjectSolverConstraint *data = con->data; - func(con, (ID **)&data->clip, false, userdata); - func(con, (ID **)&data->camera, false, userdata); + func(con, (ID **)&data->clip, false, userdata); + func(con, (ID **)&data->camera, false, userdata); } static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) { - Depsgraph *depsgraph = cob->depsgraph; - Scene *scene = cob->scene; - bObjectSolverConstraint *data = con->data; - MovieClip *clip = data->clip; - Object *camob = data->camera ? data->camera : scene->camera; + Depsgraph *depsgraph = cob->depsgraph; + Scene *scene = cob->scene; + bObjectSolverConstraint *data = con->data; + MovieClip *clip = data->clip; + Object *camob = data->camera ? data->camera : scene->camera; - if (data->flag & OBJECTSOLVER_ACTIVECLIP) - clip = scene->clip; + if (data->flag & OBJECTSOLVER_ACTIVECLIP) + clip = scene->clip; - if (!camob || !clip) - return; + if (!camob || !clip) + return; - if (clip) { - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object; + if (clip) { + MovieTracking *tracking = &clip->tracking; + MovieTrackingObject *object; - object = BKE_tracking_object_get_named(tracking, data->object); + object = BKE_tracking_object_get_named(tracking, data->object); - if (object) { - float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4], parmat[4][4]; - float ctime = DEG_get_ctime(depsgraph); - float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); + if (object) { + float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4], parmat[4][4]; + float ctime = DEG_get_ctime(depsgraph); + float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); - BKE_object_where_is_calc_mat4(camob, cammat); + BKE_object_where_is_calc_mat4(camob, cammat); - BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat); + BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat); - invert_m4_m4(camimat, cammat); - mul_m4_m4m4(parmat, cammat, data->invmat); + invert_m4_m4(camimat, cammat); + mul_m4_m4m4(parmat, cammat, data->invmat); - copy_m4_m4(cammat, camob->obmat); - copy_m4_m4(obmat, cob->matrix); + copy_m4_m4(cammat, camob->obmat); + copy_m4_m4(obmat, cob->matrix); - invert_m4_m4(imat, mat); + invert_m4_m4(imat, mat); - mul_m4_series(cob->matrix, cammat, imat, camimat, parmat, obmat); - } - } + mul_m4_series(cob->matrix, cammat, imat, camimat, parmat, obmat); + } + } } static bConstraintTypeInfo CTI_OBJECTSOLVER = { - CONSTRAINT_TYPE_OBJECTSOLVER, /* type */ - sizeof(bObjectSolverConstraint), /* size */ - "Object Solver", /* name */ - "bObjectSolverConstraint", /* struct name */ - NULL, /* free data */ - objectsolver_id_looper, /* id looper */ - NULL, /* copy data */ - objectsolver_new_data, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ - NULL, /* get target matrix */ - objectsolver_evaluate, /* evaluate */ + CONSTRAINT_TYPE_OBJECTSOLVER, /* type */ + sizeof(bObjectSolverConstraint), /* size */ + "Object Solver", /* name */ + "bObjectSolverConstraint", /* struct name */ + NULL, /* free data */ + objectsolver_id_looper, /* id looper */ + NULL, /* copy data */ + objectsolver_new_data, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + objectsolver_evaluate, /* evaluate */ }; /* ----------- Transform Cache ------------- */ static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { - bTransformCacheConstraint *data = con->data; - func(con, (ID **)&data->cache_file, true, userdata); + bTransformCacheConstraint *data = con->data; + func(con, (ID **)&data->cache_file, true, userdata); } static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { #ifdef WITH_ALEMBIC - bTransformCacheConstraint *data = con->data; - Scene *scene = cob->scene; + bTransformCacheConstraint *data = con->data; + Scene *scene = cob->scene; - CacheFile *cache_file = data->cache_file; + CacheFile *cache_file = data->cache_file; - if (!cache_file) { - return; - } + if (!cache_file) { + return; + } - const float frame = DEG_get_ctime(cob->depsgraph); - const float time = BKE_cachefile_time_offset(cache_file, frame, FPS); + const float frame = DEG_get_ctime(cob->depsgraph); + const float time = BKE_cachefile_time_offset(cache_file, frame, FPS); - /* Must always load ABC handle on original. */ - CacheFile *cache_file_orig = (CacheFile *)DEG_get_original_id(&cache_file->id); - BKE_cachefile_ensure_handle(G.main, cache_file_orig); + /* Must always load ABC handle on original. */ + CacheFile *cache_file_orig = (CacheFile *)DEG_get_original_id(&cache_file->id); + BKE_cachefile_ensure_handle(G.main, cache_file_orig); - if (!data->reader) { - data->reader = CacheReader_open_alembic_object(cache_file_orig->handle, - data->reader, - cob->ob, - data->object_path); - } + if (!data->reader) { + data->reader = CacheReader_open_alembic_object( + cache_file_orig->handle, data->reader, cob->ob, data->object_path); + } - ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale); + ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale); #else - UNUSED_VARS(con, cob); + UNUSED_VARS(con, cob); #endif - UNUSED_VARS(targets); + UNUSED_VARS(targets); } static void transformcache_copy(bConstraint *con, bConstraint *srccon) { - bTransformCacheConstraint *src = srccon->data; - bTransformCacheConstraint *dst = con->data; + bTransformCacheConstraint *src = srccon->data; + bTransformCacheConstraint *dst = con->data; - BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path)); - dst->cache_file = src->cache_file; + BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path)); + dst->cache_file = src->cache_file; #ifdef WITH_ALEMBIC - if (dst->reader) { - CacheReader_incref(dst->reader); - } + if (dst->reader) { + CacheReader_incref(dst->reader); + } #endif } static void transformcache_free(bConstraint *con) { - bTransformCacheConstraint *data = con->data; + bTransformCacheConstraint *data = con->data; - if (data->reader) { + if (data->reader) { #ifdef WITH_ALEMBIC - CacheReader_free(data->reader); + CacheReader_free(data->reader); #endif - data->reader = NULL; - } + data->reader = NULL; + } } static void transformcache_new_data(void *cdata) { - bTransformCacheConstraint *data = (bTransformCacheConstraint *)cdata; + bTransformCacheConstraint *data = (bTransformCacheConstraint *)cdata; - data->cache_file = NULL; + data->cache_file = NULL; } static bConstraintTypeInfo CTI_TRANSFORM_CACHE = { - CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */ - sizeof(bTransformCacheConstraint), /* size */ - "Transform Cache", /* name */ - "bTransformCacheConstraint", /* struct name */ - transformcache_free, /* free data */ - transformcache_id_looper, /* id looper */ - transformcache_copy, /* copy data */ - transformcache_new_data, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ - NULL, /* get target matrix */ - transformcache_evaluate, /* evaluate */ + CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */ + sizeof(bTransformCacheConstraint), /* size */ + "Transform Cache", /* name */ + "bTransformCacheConstraint", /* struct name */ + transformcache_free, /* free data */ + transformcache_id_looper, /* id looper */ + transformcache_copy, /* copy data */ + transformcache_new_data, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + transformcache_evaluate, /* evaluate */ }; /* ************************* Constraints Type-Info *************************** */ @@ -4633,37 +4796,37 @@ static short CTI_INIT = 1; /* when non-zero, the list needs to be updated */ /* This function only gets called when CTI_INIT is non-zero */ static void constraints_init_typeinfo(void) { - constraintsTypeInfo[0] = NULL; /* 'Null' Constraint */ - constraintsTypeInfo[1] = &CTI_CHILDOF; /* ChildOf Constraint */ - constraintsTypeInfo[2] = &CTI_TRACKTO; /* TrackTo Constraint */ - constraintsTypeInfo[3] = &CTI_KINEMATIC; /* IK Constraint */ - constraintsTypeInfo[4] = &CTI_FOLLOWPATH; /* Follow-Path Constraint */ - constraintsTypeInfo[5] = &CTI_ROTLIMIT; /* Limit Rotation Constraint */ - constraintsTypeInfo[6] = &CTI_LOCLIMIT; /* Limit Location Constraint */ - constraintsTypeInfo[7] = &CTI_SIZELIMIT; /* Limit Scale Constraint */ - constraintsTypeInfo[8] = &CTI_ROTLIKE; /* Copy Rotation Constraint */ - constraintsTypeInfo[9] = &CTI_LOCLIKE; /* Copy Location Constraint */ - constraintsTypeInfo[10] = &CTI_SIZELIKE; /* Copy Scale Constraint */ - constraintsTypeInfo[11] = &CTI_PYTHON; /* Python/Script Constraint */ - constraintsTypeInfo[12] = &CTI_ACTION; /* Action Constraint */ - constraintsTypeInfo[13] = &CTI_LOCKTRACK; /* Locked-Track Constraint */ - constraintsTypeInfo[14] = &CTI_DISTLIMIT; /* Limit Distance Constraint */ - constraintsTypeInfo[15] = &CTI_STRETCHTO; /* StretchTo Constaint */ - constraintsTypeInfo[16] = &CTI_MINMAX; /* Floor Constraint */ - /* constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; */ /* RigidBody Constraint - Deprecated */ - constraintsTypeInfo[18] = &CTI_CLAMPTO; /* ClampTo Constraint */ - constraintsTypeInfo[19] = &CTI_TRANSFORM; /* Transformation Constraint */ - constraintsTypeInfo[20] = &CTI_SHRINKWRAP; /* Shrinkwrap Constraint */ - constraintsTypeInfo[21] = &CTI_DAMPTRACK; /* Damped TrackTo Constraint */ - 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 */ - constraintsTypeInfo[26] = &CTI_FOLLOWTRACK; /* Follow Track Constraint */ - constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */ - constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */ - constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */ - constraintsTypeInfo[30] = &CTI_ARMATURE; /* Armature Constraint */ + constraintsTypeInfo[0] = NULL; /* 'Null' Constraint */ + constraintsTypeInfo[1] = &CTI_CHILDOF; /* ChildOf Constraint */ + constraintsTypeInfo[2] = &CTI_TRACKTO; /* TrackTo Constraint */ + constraintsTypeInfo[3] = &CTI_KINEMATIC; /* IK Constraint */ + constraintsTypeInfo[4] = &CTI_FOLLOWPATH; /* Follow-Path Constraint */ + constraintsTypeInfo[5] = &CTI_ROTLIMIT; /* Limit Rotation Constraint */ + constraintsTypeInfo[6] = &CTI_LOCLIMIT; /* Limit Location Constraint */ + constraintsTypeInfo[7] = &CTI_SIZELIMIT; /* Limit Scale Constraint */ + constraintsTypeInfo[8] = &CTI_ROTLIKE; /* Copy Rotation Constraint */ + constraintsTypeInfo[9] = &CTI_LOCLIKE; /* Copy Location Constraint */ + constraintsTypeInfo[10] = &CTI_SIZELIKE; /* Copy Scale Constraint */ + constraintsTypeInfo[11] = &CTI_PYTHON; /* Python/Script Constraint */ + constraintsTypeInfo[12] = &CTI_ACTION; /* Action Constraint */ + constraintsTypeInfo[13] = &CTI_LOCKTRACK; /* Locked-Track Constraint */ + constraintsTypeInfo[14] = &CTI_DISTLIMIT; /* Limit Distance Constraint */ + constraintsTypeInfo[15] = &CTI_STRETCHTO; /* StretchTo Constaint */ + constraintsTypeInfo[16] = &CTI_MINMAX; /* Floor Constraint */ + /* constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; */ /* RigidBody Constraint - Deprecated */ + constraintsTypeInfo[18] = &CTI_CLAMPTO; /* ClampTo Constraint */ + constraintsTypeInfo[19] = &CTI_TRANSFORM; /* Transformation Constraint */ + constraintsTypeInfo[20] = &CTI_SHRINKWRAP; /* Shrinkwrap Constraint */ + constraintsTypeInfo[21] = &CTI_DAMPTRACK; /* Damped TrackTo Constraint */ + 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 */ + constraintsTypeInfo[26] = &CTI_FOLLOWTRACK; /* Follow Track Constraint */ + constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */ + constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */ + constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */ + constraintsTypeInfo[30] = &CTI_ARMATURE; /* Armature Constraint */ } /* This function should be used for getting the appropriate type-info when only @@ -4671,24 +4834,22 @@ static void constraints_init_typeinfo(void) */ const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type) { - /* initialize the type-info list? */ - if (CTI_INIT) { - constraints_init_typeinfo(); - CTI_INIT = 0; - } + /* initialize the type-info list? */ + if (CTI_INIT) { + constraints_init_typeinfo(); + CTI_INIT = 0; + } - /* only return for valid types */ - if ((type >= CONSTRAINT_TYPE_NULL) && - (type < NUM_CONSTRAINT_TYPES)) - { - /* there shouldn't be any segfaults here... */ - return constraintsTypeInfo[type]; - } - else { - CLOG_WARN(&LOG, "No valid constraint type-info data available. Type = %i", type); - } + /* only return for valid types */ + if ((type >= CONSTRAINT_TYPE_NULL) && (type < NUM_CONSTRAINT_TYPES)) { + /* there shouldn't be any segfaults here... */ + return constraintsTypeInfo[type]; + } + else { + CLOG_WARN(&LOG, "No valid constraint type-info data available. Type = %i", type); + } - return NULL; + return NULL; } /* This function should always be used to get the appropriate type-info, as it @@ -4696,11 +4857,11 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type) */ const bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con) { - /* only return typeinfo for valid constraints */ - if (con) - return BKE_constraint_typeinfo_from_type(con->type); - else - return NULL; + /* only return typeinfo for valid constraints */ + if (con) + return BKE_constraint_typeinfo_from_type(con->type); + else + return NULL; } /* ************************* General Constraints API ************************** */ @@ -4713,10 +4874,13 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con) /** * Helper function for #BKE_constraint_free_data() - unlinks references. */ -static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool is_reference, void *UNUSED(userData)) +static void con_unlink_refs_cb(bConstraint *UNUSED(con), + ID **idpoin, + bool is_reference, + void *UNUSED(userData)) { - if (*idpoin && is_reference) - id_us_min(*idpoin); + if (*idpoin && is_reference) + id_us_min(*idpoin); } /** @@ -4726,73 +4890,73 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool is_re */ void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user) { - if (con->data) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + if (con->data) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - if (cti) { - /* perform any special freeing constraint may have */ - if (cti->free_data) - cti->free_data(con); + if (cti) { + /* perform any special freeing constraint may have */ + if (cti->free_data) + cti->free_data(con); - /* unlink the referenced resources it uses */ - if (do_id_user && cti->id_looper) - cti->id_looper(con, con_unlink_refs_cb, NULL); - } + /* unlink the referenced resources it uses */ + if (do_id_user && cti->id_looper) + cti->id_looper(con, con_unlink_refs_cb, NULL); + } - /* free constraint data now */ - MEM_freeN(con->data); - } + /* free constraint data now */ + MEM_freeN(con->data); + } } void BKE_constraint_free_data(bConstraint *con) { - BKE_constraint_free_data_ex(con, true); + BKE_constraint_free_data_ex(con, true); } /* Free all constraints from a constraint-stack */ void BKE_constraints_free_ex(ListBase *list, bool do_id_user) { - bConstraint *con; + bConstraint *con; - /* Free constraint data and also any extra data */ - for (con = list->first; con; con = con->next) - BKE_constraint_free_data_ex(con, do_id_user); + /* Free constraint data and also any extra data */ + for (con = list->first; con; con = con->next) + BKE_constraint_free_data_ex(con, do_id_user); - /* Free the whole list */ - BLI_freelistN(list); + /* Free the whole list */ + BLI_freelistN(list); } void BKE_constraints_free(ListBase *list) { - BKE_constraints_free_ex(list, true); + BKE_constraints_free_ex(list, true); } /* Remove the specified constraint from the given constraint stack */ bool BKE_constraint_remove(ListBase *list, bConstraint *con) { - if (con) { - BKE_constraint_free_data(con); - BLI_freelinkN(list, con); - return true; - } - else { - return false; - } + if (con) { + BKE_constraint_free_data(con); + BLI_freelinkN(list, con); + return true; + } + else { + return false; + } } bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool clear_dep) { - const short type = con->type; - if (BKE_constraint_remove(list, con)) { - /* ITASC needs to be rebuilt once a constraint is removed [#26920] */ - if (clear_dep && ELEM(type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) { - BIK_clear_data(ob->pose); - } - return true; - } - else { - return false; - } + const short type = con->type; + if (BKE_constraint_remove(list, con)) { + /* ITASC needs to be rebuilt once a constraint is removed [#26920] */ + if (clear_dep && ELEM(type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) { + BIK_clear_data(ob->pose); + } + return true; + } + else { + return false; + } } /* ......... */ @@ -4800,108 +4964,114 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool /* Creates a new constraint, initializes its data, and returns it */ static bConstraint *add_new_constraint_internal(const char *name, short type) { - bConstraint *con = MEM_callocN(sizeof(bConstraint), "Constraint"); - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(type); - const char *newName; + bConstraint *con = MEM_callocN(sizeof(bConstraint), "Constraint"); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(type); + const char *newName; - /* Set up a generic constraint datablock */ - con->type = type; - con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_STATICOVERRIDE_LOCAL; - con->enforce = 1.0f; + /* Set up a generic constraint datablock */ + con->type = type; + con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_STATICOVERRIDE_LOCAL; + con->enforce = 1.0f; - /* Determine a basic name, and info */ - if (cti) { - /* initialize constraint data */ - con->data = MEM_callocN(cti->size, cti->structName); + /* Determine a basic name, and info */ + if (cti) { + /* initialize constraint data */ + con->data = MEM_callocN(cti->size, cti->structName); - /* only constraints that change any settings need this */ - if (cti->new_data) - cti->new_data(con->data); + /* only constraints that change any settings need this */ + if (cti->new_data) + cti->new_data(con->data); - /* if no name is provided, use the type of the constraint as the name */ - newName = (name && name[0]) ? name : DATA_(cti->name); - } - else { - /* if no name is provided, use the generic "Const" name */ - /* NOTE: any constraint type that gets here really shouldn't get added... */ - newName = (name && name[0]) ? name : DATA_("Const"); - } + /* if no name is provided, use the type of the constraint as the name */ + newName = (name && name[0]) ? name : DATA_(cti->name); + } + else { + /* if no name is provided, use the generic "Const" name */ + /* NOTE: any constraint type that gets here really shouldn't get added... */ + newName = (name && name[0]) ? name : DATA_("Const"); + } - /* copy the name */ - BLI_strncpy(con->name, newName, sizeof(con->name)); + /* copy the name */ + BLI_strncpy(con->name, newName, sizeof(con->name)); - /* return the new constraint */ - return con; + /* return the new constraint */ + return con; } /* if pchan is not NULL then assume we're adding a pose constraint */ -static bConstraint *add_new_constraint(Object *ob, bPoseChannel *pchan, const char *name, short type) +static bConstraint *add_new_constraint(Object *ob, + bPoseChannel *pchan, + const char *name, + short type) { - bConstraint *con; - ListBase *list; + bConstraint *con; + ListBase *list; - /* add the constraint */ - con = add_new_constraint_internal(name, type); + /* add the constraint */ + con = add_new_constraint_internal(name, type); - /* find the constraint stack - bone or object? */ - list = (pchan) ? (&pchan->constraints) : (&ob->constraints); + /* find the constraint stack - bone or object? */ + list = (pchan) ? (&pchan->constraints) : (&ob->constraints); - if (list) { - /* add new constraint to end of list of constraints before ensuring that it has a unique name - * (otherwise unique-naming code will fail, since it assumes element exists in list) - */ - BLI_addtail(list, con); - BKE_constraint_unique_name(con, list); + if (list) { + /* add new constraint to end of list of constraints before ensuring that it has a unique name + * (otherwise unique-naming code will fail, since it assumes element exists in list) + */ + BLI_addtail(list, con); + BKE_constraint_unique_name(con, list); - /* if the target list is a list on some PoseChannel belonging to a proxy-protected - * Armature layer, we must tag newly added constraints with a flag which allows them - * to persist after proxy syncing has been done - */ - if (BKE_constraints_proxylocked_owner(ob, pchan)) - con->flag |= CONSTRAINT_PROXY_LOCAL; + /* if the target list is a list on some PoseChannel belonging to a proxy-protected + * Armature layer, we must tag newly added constraints with a flag which allows them + * to persist after proxy syncing has been done + */ + if (BKE_constraints_proxylocked_owner(ob, pchan)) + con->flag |= CONSTRAINT_PROXY_LOCAL; - /* make this constraint the active one */ - BKE_constraints_active_set(list, con); - } + /* make this constraint the active one */ + BKE_constraints_active_set(list, con); + } - /* set type+owner specific immutable settings */ - /* TODO: does action constraint need anything here - i.e. spaceonce? */ - switch (type) { - case CONSTRAINT_TYPE_CHILDOF: - { - /* if this constraint is being added to a posechannel, make sure - * the constraint gets evaluated in pose-space */ - if (pchan) { - con->ownspace = CONSTRAINT_SPACE_POSE; - con->flag |= CONSTRAINT_SPACEONCE; - } - break; - } - } + /* set type+owner specific immutable settings */ + /* TODO: does action constraint need anything here - i.e. spaceonce? */ + switch (type) { + case CONSTRAINT_TYPE_CHILDOF: { + /* if this constraint is being added to a posechannel, make sure + * the constraint gets evaluated in pose-space */ + if (pchan) { + con->ownspace = CONSTRAINT_SPACE_POSE; + con->flag |= CONSTRAINT_SPACEONCE; + } + break; + } + } - return con; + return con; } -bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *UNUSED(ct)) +bool BKE_constraint_target_uses_bbone(struct bConstraint *con, + struct bConstraintTarget *UNUSED(ct)) { - return (con->flag & CONSTRAINT_BBONE_SHAPE) || (con->type == CONSTRAINT_TYPE_ARMATURE); + return (con->flag & CONSTRAINT_BBONE_SHAPE) || (con->type == CONSTRAINT_TYPE_ARMATURE); } /* ......... */ /* Add new constraint for the given bone */ -bConstraint *BKE_constraint_add_for_pose(Object *ob, bPoseChannel *pchan, const char *name, short type) +bConstraint *BKE_constraint_add_for_pose(Object *ob, + bPoseChannel *pchan, + const char *name, + short type) { - if (pchan == NULL) - return NULL; + if (pchan == NULL) + return NULL; - return add_new_constraint(ob, pchan, name, type); + return add_new_constraint(ob, pchan, name, type); } /* Add new constraint for the given object */ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short type) { - return add_new_constraint(ob, NULL, name, type); + return add_new_constraint(ob, NULL, name, type); } /* ......... */ @@ -4909,240 +5079,255 @@ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short t /* Run the given callback on all ID-blocks in list of constraints */ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata) { - bConstraint *con; + bConstraint *con; - for (con = conlist->first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + for (con = conlist->first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - if (cti) { - if (cti->id_looper) - cti->id_looper(con, func, userdata); - } - } + if (cti) { + if (cti->id_looper) + cti->id_looper(con, func, userdata); + } + } } /* ......... */ /* helper for BKE_constraints_copy(), to be used for making sure that ID's are valid */ -static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userData)) +static void con_extern_cb(bConstraint *UNUSED(con), + ID **idpoin, + bool UNUSED(is_reference), + void *UNUSED(userData)) { - if (*idpoin && ID_IS_LINKED(*idpoin)) - id_lib_extern(*idpoin); + if (*idpoin && ID_IS_LINKED(*idpoin)) + id_lib_extern(*idpoin); } /* helper for BKE_constraints_copy(), to be used for making sure that usercounts of copied ID's are fixed up */ -static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool is_reference, void *UNUSED(userData)) +static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), + ID **idpoin, + bool is_reference, + void *UNUSED(userData)) { - /* increment usercount if this is a reference type */ - if ((*idpoin) && (is_reference)) - id_us_plus(*idpoin); + /* increment usercount if this is a reference type */ + if ((*idpoin) && (is_reference)) + id_us_plus(*idpoin); } /** Copies a single constraint's data (\a dst must already be a shallow copy of \a src). */ -static void constraint_copy_data_ex(bConstraint *dst, bConstraint *src, const int flag, const bool do_extern) +static void constraint_copy_data_ex(bConstraint *dst, + bConstraint *src, + const int flag, + const bool do_extern) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(src); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(src); - /* make a new copy of the constraint's data */ - dst->data = MEM_dupallocN(dst->data); + /* make a new copy of the constraint's data */ + dst->data = MEM_dupallocN(dst->data); - /* only do specific constraints if required */ - if (cti) { - /* perform custom copying operations if needed */ - if (cti->copy_data) - cti->copy_data(dst, src); + /* only do specific constraints if required */ + if (cti) { + /* perform custom copying operations if needed */ + if (cti->copy_data) + cti->copy_data(dst, src); - /* Fix usercounts for all referenced data that need it. */ - if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - cti->id_looper(dst, con_fix_copied_refs_cb, NULL); - } + /* Fix usercounts for all referenced data that need it. */ + if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + cti->id_looper(dst, con_fix_copied_refs_cb, NULL); + } - /* for proxies we don't want to make extern */ - if (do_extern) { - /* go over used ID-links for this constraint to ensure that they are valid for proxies */ - if (cti->id_looper) - cti->id_looper(dst, con_extern_cb, NULL); - } - } + /* for proxies we don't want to make extern */ + if (do_extern) { + /* go over used ID-links for this constraint to ensure that they are valid for proxies */ + if (cti->id_looper) + cti->id_looper(dst, con_extern_cb, NULL); + } + } } /** Allocate and duplicate a single constraint, ouside of any object/pose context. */ bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bool do_extern) { - bConstraint *dst = MEM_dupallocN(src); - constraint_copy_data_ex(dst, src, flag, do_extern); - dst->next = dst->prev = NULL; - return dst; + bConstraint *dst = MEM_dupallocN(src); + constraint_copy_data_ex(dst, src, flag, do_extern); + dst->next = dst->prev = NULL; + return dst; } /* duplicate all of the constraints in a constraint stack */ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern) { - bConstraint *con, *srccon; + bConstraint *con, *srccon; - BLI_listbase_clear(dst); - BLI_duplicatelist(dst, src); + BLI_listbase_clear(dst); + BLI_duplicatelist(dst, src); - for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) { - constraint_copy_data_ex(con, srccon, flag, do_extern); - } + for (con = dst->first, srccon = src->first; con && srccon; + srccon = srccon->next, con = con->next) { + constraint_copy_data_ex(con, srccon, flag, do_extern); + } } void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern) { - BKE_constraints_copy_ex(dst, src, 0, do_extern); + BKE_constraints_copy_ex(dst, src, 0, do_extern); } /* ......... */ bConstraint *BKE_constraints_find_name(ListBase *list, const char *name) { - return BLI_findstring(list, name, offsetof(bConstraint, name)); + return BLI_findstring(list, name, offsetof(bConstraint, name)); } /* finds the 'active' constraint in a constraint stack */ bConstraint *BKE_constraints_active_get(ListBase *list) { - bConstraint *con; + bConstraint *con; - /* search for the first constraint with the 'active' flag set */ - if (list) { - for (con = list->first; con; con = con->next) { - if (con->flag & CONSTRAINT_ACTIVE) - return con; - } - } + /* search for the first constraint with the 'active' flag set */ + if (list) { + for (con = list->first; con; con = con->next) { + if (con->flag & CONSTRAINT_ACTIVE) + return con; + } + } - /* no active constraint found */ - return NULL; + /* no active constraint found */ + return NULL; } /* Set the given constraint as the active one (clearing all the others) */ void BKE_constraints_active_set(ListBase *list, bConstraint *con) { - bConstraint *c; + bConstraint *c; - if (list) { - for (c = list->first; c; c = c->next) { - if (c == con) - c->flag |= CONSTRAINT_ACTIVE; - else - c->flag &= ~CONSTRAINT_ACTIVE; - } - } + if (list) { + for (c = list->first; c; c = c->next) { + if (c == con) + c->flag |= CONSTRAINT_ACTIVE; + else + c->flag &= ~CONSTRAINT_ACTIVE; + } + } } static bConstraint *constraint_list_find_from_target(ListBase *constraints, bConstraintTarget *tgt) { - for (bConstraint *con = constraints->first; con; con = con->next) { - ListBase *targets = NULL; + for (bConstraint *con = constraints->first; con; con = con->next) { + ListBase *targets = NULL; - if (con->type == CONSTRAINT_TYPE_PYTHON) { - targets = &((bPythonConstraint *)con->data)->targets; - } - else if (con->type == CONSTRAINT_TYPE_ARMATURE) { - targets = &((bArmatureConstraint *)con->data)->targets; - } + if (con->type == CONSTRAINT_TYPE_PYTHON) { + targets = &((bPythonConstraint *)con->data)->targets; + } + else if (con->type == CONSTRAINT_TYPE_ARMATURE) { + targets = &((bArmatureConstraint *)con->data)->targets; + } - if (targets && BLI_findindex(targets, tgt) != -1) { - return con; - } - } + if (targets && BLI_findindex(targets, tgt) != -1) { + return con; + } + } - return NULL; + return NULL; } /* Finds the constraint that owns the given target within the object. */ -bConstraint *BKE_constraint_find_from_target(Object *ob, bConstraintTarget *tgt, bPoseChannel **r_pchan) +bConstraint *BKE_constraint_find_from_target(Object *ob, + bConstraintTarget *tgt, + bPoseChannel **r_pchan) { - if (r_pchan != NULL) { - *r_pchan = NULL; - } + if (r_pchan != NULL) { + *r_pchan = NULL; + } - bConstraint *result = constraint_list_find_from_target(&ob->constraints, tgt); + bConstraint *result = constraint_list_find_from_target(&ob->constraints, tgt); - if (result != NULL) { - return result; - } + if (result != NULL) { + return result; + } - if (ob->pose != NULL) { - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - result = constraint_list_find_from_target(&pchan->constraints, tgt); + if (ob->pose != NULL) { + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + result = constraint_list_find_from_target(&pchan->constraints, tgt); - if (result != NULL) { - if (r_pchan != NULL) { - *r_pchan = pchan; - } + if (result != NULL) { + if (r_pchan != NULL) { + *r_pchan = pchan; + } - return result; - } - } - } + return result; + } + } + } - return NULL; + return NULL; } /* Finds the original copy of the constraint based on a COW copy. */ -static bConstraint *constraint_find_original(Object *ob, bPoseChannel *pchan, bConstraint *con, Object **r_orig_ob) +static bConstraint *constraint_find_original(Object *ob, + bPoseChannel *pchan, + bConstraint *con, + Object **r_orig_ob) { - Object *orig_ob = (Object *)DEG_get_original_id(&ob->id); + Object *orig_ob = (Object *)DEG_get_original_id(&ob->id); - if (ELEM(orig_ob, NULL, ob)) { - return NULL; - } + if (ELEM(orig_ob, NULL, ob)) { + return NULL; + } - /* Find which constraint list to use. */ - ListBase *constraints, *orig_constraints; + /* Find which constraint list to use. */ + ListBase *constraints, *orig_constraints; - if (pchan != NULL) { - bPoseChannel *orig_pchan = pchan->orig_pchan; + if (pchan != NULL) { + bPoseChannel *orig_pchan = pchan->orig_pchan; - if (orig_pchan == NULL) { - return NULL; - } + if (orig_pchan == NULL) { + return NULL; + } - constraints = &pchan->constraints; - orig_constraints = &orig_pchan->constraints; - } - else { - constraints = &ob->constraints; - orig_constraints = &orig_ob->constraints; - } + constraints = &pchan->constraints; + orig_constraints = &orig_pchan->constraints; + } + else { + constraints = &ob->constraints; + orig_constraints = &orig_ob->constraints; + } - /* Lookup the original constraint by index. */ - int index = BLI_findindex(constraints, con); + /* Lookup the original constraint by index. */ + int index = BLI_findindex(constraints, con); - if (index >= 0) { - bConstraint *orig_con = BLI_findlink(orig_constraints, index); + if (index >= 0) { + bConstraint *orig_con = BLI_findlink(orig_constraints, index); - /* Verify it has correct type and name. */ - if (orig_con && orig_con->type == con->type && STREQ(orig_con->name, con->name)) { - if (r_orig_ob != NULL) { - *r_orig_ob = orig_ob; - } + /* Verify it has correct type and name. */ + if (orig_con && orig_con->type == con->type && STREQ(orig_con->name, con->name)) { + if (r_orig_ob != NULL) { + *r_orig_ob = orig_ob; + } - return orig_con; - } - } + return orig_con; + } + } - return NULL; + return NULL; } static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bConstraint *con) { - /* Write the computed distance back to the master copy if in COW evaluation. */ - if (!DEG_is_active(cob->depsgraph)) { - return NULL; - } + /* Write the computed distance back to the master copy if in COW evaluation. */ + if (!DEG_is_active(cob->depsgraph)) { + return NULL; + } - Object *orig_ob = NULL; - bConstraint *orig_con = constraint_find_original(cob->ob, cob->pchan, con, &orig_ob); + Object *orig_ob = NULL; + bConstraint *orig_con = constraint_find_original(cob->ob, cob->pchan, con, &orig_ob); - if (orig_con != NULL) { - DEG_id_tag_update(&orig_ob->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM); - } + if (orig_con != NULL) { + DEG_id_tag_update(&orig_ob->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM); + } - return orig_con; + return orig_con; } /* -------- Constraints and Proxies ------- */ @@ -5150,39 +5335,39 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon /* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL (i.e. added to bone that's proxy-synced in this file) */ void BKE_constraints_proxylocal_extract(ListBase *dst, ListBase *src) { - bConstraint *con, *next; + bConstraint *con, *next; - /* for each tagged constraint, remove from src and move to dst */ - for (con = src->first; con; con = next) { - next = con->next; + /* for each tagged constraint, remove from src and move to dst */ + for (con = src->first; con; con = next) { + next = con->next; - /* check if tagged */ - if (con->flag & CONSTRAINT_PROXY_LOCAL) { - BLI_remlink(src, con); - BLI_addtail(dst, con); - } - } + /* check if tagged */ + if (con->flag & CONSTRAINT_PROXY_LOCAL) { + BLI_remlink(src, con); + BLI_addtail(dst, con); + } + } } /* Returns if the owner of the constraint is proxy-protected */ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan) { - /* Currently, constraints can only be on object or bone level */ - if (ob && ob->proxy) { - if (ob->pose && pchan) { - bArmature *arm = ob->data; + /* Currently, constraints can only be on object or bone level */ + if (ob && ob->proxy) { + if (ob->pose && pchan) { + bArmature *arm = ob->data; - /* On bone-level, check if bone is on proxy-protected layer */ - if ((pchan->bone) && (pchan->bone->layer & arm->layer_protected)) - return true; - } - else { - /* FIXME: constraints on object-level are not handled well yet */ - return true; - } - } + /* On bone-level, check if bone is on proxy-protected layer */ + if ((pchan->bone) && (pchan->bone->layer & arm->layer_protected)) + return true; + } + else { + /* FIXME: constraints on object-level are not handled well yet */ + return true; + } + } - return false; + return false; } /* -------- Target-Matrix Stuff ------- */ @@ -5194,99 +5379,110 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan) * None of the actual calculations of the matrices should be done here! Also, this function is * not to be used by any new constraints, particularly any that have multiple targets. */ -void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime) -{ - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintOb *cob; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - /* make 'constraint-ob' */ - cob = MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb"); - cob->type = ownertype; - cob->scene = scene; - cob->depsgraph = depsgraph; - switch (ownertype) { - case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */ - { - cob->ob = (Object *)ownerdata; - cob->pchan = NULL; - if (cob->ob) { - copy_m4_m4(cob->matrix, cob->ob->obmat); - copy_m4_m4(cob->startmat, cob->matrix); - } - else { - unit_m4(cob->matrix); - unit_m4(cob->startmat); - } - break; - } - case CONSTRAINT_OBTYPE_BONE: /* this may occur in some cases */ - { - cob->ob = NULL; /* this might not work at all :/ */ - cob->pchan = (bPoseChannel *)ownerdata; - if (cob->pchan) { - copy_m4_m4(cob->matrix, cob->pchan->pose_mat); - copy_m4_m4(cob->startmat, cob->matrix); - } - else { - unit_m4(cob->matrix); - unit_m4(cob->startmat); - } - break; - } - } - - /* get targets - we only need the first one though (and there should only be one) */ - cti->get_constraint_targets(con, &targets); - - /* only calculate the target matrix on the first target */ - ct = BLI_findlink(&targets, index); - - if (ct) { - if (cti->get_target_matrix) - cti->get_target_matrix(depsgraph, con, cob, ct, ctime); - copy_m4_m4(mat, ct->matrix); - } - - /* free targets + 'constraint-ob' */ - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - MEM_freeN(cob); - } - else { - /* invalid constraint - perhaps... */ - unit_m4(mat); - } +void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, + Scene *scene, + bConstraint *con, + int index, + short ownertype, + void *ownerdata, + float mat[4][4], + float ctime) +{ + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + ListBase targets = {NULL, NULL}; + bConstraintOb *cob; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + /* make 'constraint-ob' */ + cob = MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb"); + cob->type = ownertype; + cob->scene = scene; + cob->depsgraph = depsgraph; + switch (ownertype) { + case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */ + { + cob->ob = (Object *)ownerdata; + cob->pchan = NULL; + if (cob->ob) { + copy_m4_m4(cob->matrix, cob->ob->obmat); + copy_m4_m4(cob->startmat, cob->matrix); + } + else { + unit_m4(cob->matrix); + unit_m4(cob->startmat); + } + break; + } + case CONSTRAINT_OBTYPE_BONE: /* this may occur in some cases */ + { + cob->ob = NULL; /* this might not work at all :/ */ + cob->pchan = (bPoseChannel *)ownerdata; + if (cob->pchan) { + copy_m4_m4(cob->matrix, cob->pchan->pose_mat); + copy_m4_m4(cob->startmat, cob->matrix); + } + else { + unit_m4(cob->matrix); + unit_m4(cob->startmat); + } + break; + } + } + + /* get targets - we only need the first one though (and there should only be one) */ + cti->get_constraint_targets(con, &targets); + + /* only calculate the target matrix on the first target */ + ct = BLI_findlink(&targets, index); + + if (ct) { + if (cti->get_target_matrix) + cti->get_target_matrix(depsgraph, con, cob, ct, ctime); + copy_m4_m4(mat, ct->matrix); + } + + /* free targets + 'constraint-ob' */ + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 1); + MEM_freeN(cob); + } + else { + /* invalid constraint - perhaps... */ + unit_m4(mat); + } } /* Get the list of targets required for solving a constraint */ -void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime) -{ - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - - if (cti && cti->get_constraint_targets) { - bConstraintTarget *ct; - - /* get targets - * - constraints should use ct->matrix, not directly accessing values - * - ct->matrix members have not yet been calculated here! - */ - cti->get_constraint_targets(con, targets); - - /* set matrices - * - calculate if possible, otherwise just initialize as identity matrix - */ - if (cti->get_target_matrix) { - for (ct = targets->first; ct; ct = ct->next) - cti->get_target_matrix(depsgraph, con, cob, ct, ctime); - } - else { - for (ct = targets->first; ct; ct = ct->next) - unit_m4(ct->matrix); - } - } +void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, + bConstraint *con, + bConstraintOb *cob, + ListBase *targets, + float ctime) +{ + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + + if (cti && cti->get_constraint_targets) { + bConstraintTarget *ct; + + /* get targets + * - constraints should use ct->matrix, not directly accessing values + * - ct->matrix members have not yet been calculated here! + */ + cti->get_constraint_targets(con, targets); + + /* set matrices + * - calculate if possible, otherwise just initialize as identity matrix + */ + if (cti->get_target_matrix) { + for (ct = targets->first; ct; ct = ct->next) + cti->get_target_matrix(depsgraph, con, cob, ct, ctime); + } + else { + for (ct = targets->first; ct; ct = ct->next) + unit_m4(ct->matrix); + } + } } /* ---------- Evaluation ----------- */ @@ -5297,69 +5493,78 @@ void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, bConstr * BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and * after running this function, to sort out cob */ -void BKE_constraints_solve(struct Depsgraph *depsgraph, ListBase *conlist, bConstraintOb *cob, float ctime) -{ - bConstraint *con; - float oldmat[4][4]; - float enf; - - /* check that there is a valid constraint object to evaluate */ - if (cob == NULL) - return; - - /* loop over available constraints, solving and blending them */ - for (con = conlist->first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - - /* these we can skip completely (invalid constraints...) */ - if (cti == NULL) continue; - if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) continue; - /* these constraints can't be evaluated anyway */ - if (cti->evaluate_constraint == NULL) continue; - /* influence == 0 should be ignored */ - if (con->enforce == 0.0f) continue; - - /* influence of constraint - * - value should have been set from animation data already - */ - enf = con->enforce; - - /* make copy of worldspace matrix pre-constraint for use with blending later */ - copy_m4_m4(oldmat, cob->matrix); - - /* move owner matrix into right space */ - BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false); - - /* prepare targets for constraint solving */ - BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime); - - /* Solve the constraint and put result in cob->matrix */ - cti->evaluate_constraint(con, cob, &targets); - - /* clear targets after use - * - this should free temp targets but no data should be copied back - * as constraints may have done some nasty things to it... - */ - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 1); - } - - /* move owner back into worldspace for next constraint/other business */ - if ((con->flag & CONSTRAINT_SPACEONCE) == 0) - BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false); - - /* Interpolate the enforcement, to blend result of constraint into final owner transform - * - all this happens in worldspace to prevent any weirdness creeping in ([#26014] and [#25725]), - * since some constraints may not convert the solution back to the input space before blending - * but all are guaranteed to end up in good "worldspace" result - */ - /* Note: all kind of stuff here before (caused trouble), much easier to just interpolate, - * or did I miss something? -jahka (r.32105) */ - if (enf < 1.0f) { - float solution[4][4]; - copy_m4_m4(solution, cob->matrix); - interp_m4_m4m4(cob->matrix, oldmat, solution, enf); - } - } +void BKE_constraints_solve(struct Depsgraph *depsgraph, + ListBase *conlist, + bConstraintOb *cob, + float ctime) +{ + bConstraint *con; + float oldmat[4][4]; + float enf; + + /* check that there is a valid constraint object to evaluate */ + if (cob == NULL) + return; + + /* loop over available constraints, solving and blending them */ + for (con = conlist->first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + ListBase targets = {NULL, NULL}; + + /* these we can skip completely (invalid constraints...) */ + if (cti == NULL) + continue; + if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) + continue; + /* these constraints can't be evaluated anyway */ + if (cti->evaluate_constraint == NULL) + continue; + /* influence == 0 should be ignored */ + if (con->enforce == 0.0f) + continue; + + /* influence of constraint + * - value should have been set from animation data already + */ + enf = con->enforce; + + /* make copy of worldspace matrix pre-constraint for use with blending later */ + copy_m4_m4(oldmat, cob->matrix); + + /* move owner matrix into right space */ + BKE_constraint_mat_convertspace( + cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false); + + /* prepare targets for constraint solving */ + BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime); + + /* Solve the constraint and put result in cob->matrix */ + cti->evaluate_constraint(con, cob, &targets); + + /* clear targets after use + * - this should free temp targets but no data should be copied back + * as constraints may have done some nasty things to it... + */ + if (cti->flush_constraint_targets) { + cti->flush_constraint_targets(con, &targets, 1); + } + + /* move owner back into worldspace for next constraint/other business */ + if ((con->flag & CONSTRAINT_SPACEONCE) == 0) + BKE_constraint_mat_convertspace( + cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false); + + /* Interpolate the enforcement, to blend result of constraint into final owner transform + * - all this happens in worldspace to prevent any weirdness creeping in ([#26014] and [#25725]), + * since some constraints may not convert the solution back to the input space before blending + * but all are guaranteed to end up in good "worldspace" result + */ + /* Note: all kind of stuff here before (caused trouble), much easier to just interpolate, + * or did I miss something? -jahka (r.32105) */ + if (enf < 1.0f) { + float solution[4][4]; + copy_m4_m4(solution, cob->matrix); + interp_m4_m4m4(cob->matrix, oldmat, solution, enf); + } + } } |