Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/constraint.c')
-rw-r--r--source/blender/blenkernel/intern/constraint.c8053
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(&params);
- BKE_camera_params_from_object(&params, 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(&params);
+ BKE_camera_params_from_object(&params, 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);
+ }
+ }
}