Cycles: svn merge -r39870:r40266 https://svn.blender.org/svnroot/bf-blender/trunk...
[blender-staging.git] / source / blender / blenkernel / intern / constraint.c
index ba5b7e3ae4ad292c1f4d073d69aa896785b2d9d0..91091d3880f5774ec6232dd7746e01e52dc53dcf 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -424,7 +422,7 @@ void constraint_mat_convertspace (Object *ob, bPoseChannel *pchan, float mat[][4
 /* ------------ General Target Matrix Tools ---------- */
 
 /* function that sets the given matrix based on given vertex group in mesh */
-static void contarget_get_mesh_mat (Scene *scene, Object *ob, const char *substring, float mat[][4])
+static void contarget_get_mesh_mat (Object *ob, const char *substring, float mat[][4])
 {
        DerivedMesh *dm = NULL;
        Mesh *me= ob->data;
@@ -449,16 +447,9 @@ static void contarget_get_mesh_mat (Scene *scene, Object *ob, const char *substr
                freeDM= 1;
        }
        else {
-               /* when not in EditMode, use the 'final' derived mesh 
-                *      - check if the custom data masks for derivedFinal mean that we can just use that
-                *        (this is more effficient + sufficient for most cases)
-                */
-               if (!(ob->lastDataMask & CD_MASK_MDEFORMVERT)) {
-                       dm = mesh_get_derived_final(scene, ob, CD_MASK_MDEFORMVERT);
-                       freeDM= 1;
-               }
-               else 
-                       dm = (DerivedMesh *)ob->derivedFinal;
+               /* when not in EditMode, use the 'final' derived mesh, depsgraph
+                * ensures we build with CD_MDEFORMVERT layer */
+               dm = (DerivedMesh *)ob->derivedFinal;
        }
        
        /* only continue if there's a valid DerivedMesh */
@@ -587,7 +578,7 @@ static void contarget_get_lattice_mat (Object *ob, const char *substring, float
 
 /* 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 (Scene *scene, Object *ob, const char *substring, float mat[][4], short from, short to, float headtail)
+static void constraint_target_to_mat4 (Object *ob, const char *substring, float mat[][4], short from, short to, float headtail)
 {
        /*      Case OBJECT */
        if (!strlen(substring)) {
@@ -604,7 +595,7 @@ static void constraint_target_to_mat4 (Scene *scene, Object *ob, const char *sub
         *              way as constraints can only really affect things on object/bone level.
         */
        else if (ob->type == OB_MESH) {
-               contarget_get_mesh_mat(scene, ob, substring, mat);
+               contarget_get_mesh_mat(ob, substring, mat);
                constraint_mat_convertspace(ob, NULL, mat, from, to);
        }
        else if (ob->type == OB_LATTICE) {
@@ -621,7 +612,7 @@ static void constraint_target_to_mat4 (Scene *scene, Object *ob, const char *sub
                         * PoseChannel by the Armature Object's Matrix to get a worldspace
                         * matrix.
                         */
-                       if (headtail < 0.000001) {
+                       if (headtail < 0.000001f) {
                                /* skip length interpolation if set to head */
                                mul_m4_m4m4(mat, pchan->pose_mat, ob->obmat);
                        }
@@ -684,10 +675,10 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
 /* 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 (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void default_get_tarmat (bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
 {
        if (VALID_CONS_TARGET(ct))
-               constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+               constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
        else if (ct)
                unit_m4(ct->matrix);
 }
@@ -994,10 +985,10 @@ static void vectomat (float *vec, float *target_up, short axis, short upflag, sh
        float neg = -1;
        int right_index;
 
-       if (normalize_v3_v3(n, vec) == 0.0) { 
-               n[0] = 0.0;
-               n[1] = 0.0;
-               n[2] = 1.0;
+       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);
@@ -1019,10 +1010,10 @@ static void vectomat (float *vec, float *target_up, short axis, short upflag, sh
        sub_v3_v3v3(proj, u, proj); /* then onto the plane */
        /* proj specifies the transformation of the up axis */
 
-       if (normalize_v3(proj) == 0.0) { /* degenerate projection */
-               proj[0] = 0.0;
-               proj[1] = 1.0;
-               proj[2] = 0.0;
+       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 */
@@ -1159,7 +1150,7 @@ static void kinematic_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstra
        bKinematicConstraint *data= con->data;
        
        if (VALID_CONS_TARGET(ct)) 
-               constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+               constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
        else if (ct) {
                if (data->flag & CONSTRAINT_IK_AUTO) {
                        Object *ob= cob->ob;
@@ -1278,7 +1269,7 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr
                                 * factor, which then gets clamped to lie within 0.0 - 1.0 range
                                 */
                                curvetime /= cu->pathlen;
-                               CLAMP(curvetime, 0.0, 1.0);
+                               CLAMP(curvetime, 0.0f, 1.0f);
                        }
                        else {
                                /* fixed position along curve */
@@ -1925,7 +1916,7 @@ static void samevolume_evaluate (bConstraint *con, bConstraintOb *cob, ListBase
        
        /* calculate normalising scale factor for non-essential values */
        if (obsize[data->flag] != 0) 
-               fac = sqrt(volume / obsize[data->flag]) / obsize[data->flag];
+               fac = sqrtf(volume / obsize[data->flag]) / obsize[data->flag];
        
        /* apply scaling factor to the channels not being kept */
        switch (data->flag) {
@@ -2046,7 +2037,7 @@ static void pycon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintT
                /* 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(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+               constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
                
                /* only execute target calculation if allowed */
 #ifdef WITH_PYTHON
@@ -2165,7 +2156,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint
                unit_m4(ct->matrix);
                
                /* get the transform matrix of the target */
-               constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+               constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
                
                /* determine where in transform range target is */
                /* data->type is mapped as follows for backwards compatability:
@@ -2176,9 +2167,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint
                if (data->type < 10) {
                        /* extract rotation (is in whatever space target should be in) */
                        mat4_to_eul(vec, tempmat);
-                       vec[0] *= (float)(180.0/M_PI);
-                       vec[1] *= (float)(180.0/M_PI);
-                       vec[2] *= (float)(180.0/M_PI);
+                       mul_v3_fl(vec, (float)(180.0/M_PI)); /* rad -> deg */
                        axis= data->type;
                }
                else if (data->type < 20) {
@@ -2218,7 +2207,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint
                        tchan->rotmode= pchan->rotmode;
                        
                        /* evaluate action using workob (it will only set the PoseChannel in question) */
-                       what_does_obaction(cob->scene, cob->ob, &workob, pose, data->act, pchan->name, t);
+                       what_does_obaction(cob->ob, &workob, pose, data->act, pchan->name, t);
                        
                        /* convert animation to matrices for use here */
                        pchan_calc_mat(tchan);
@@ -2232,7 +2221,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint
                        
                        /* evaluate using workob */
                        // FIXME: we don't have any consistent standards on limiting effects on object...
-                       what_does_obaction(cob->scene, cob->ob, &workob, NULL, data->act, NULL, t);
+                       what_does_obaction(cob->ob, &workob, NULL, data->act, NULL, t);
                        object_to_mat4(&workob, ct->matrix);
                }
                else {
@@ -2650,7 +2639,7 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *
                        /* if inside, then move to surface */
                        if (dist <= data->dist) {
                                clamp_surf= 1;
-                               sfac= data->dist / dist;
+                               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) {
@@ -2663,23 +2652,23 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *
                        /* if outside, then move to surface */
                        if (dist >= data->dist) {
                                clamp_surf= 1;
-                               sfac= data->dist / dist;
+                               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.0 - exp(-(dist - data->dist)/data->soft)) + data->dist );
-                                       sfac /= dist;
+                                       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_EQ(dist, data->dist)==0) {
+                       if (IS_EQF(dist, data->dist)==0) {
                                clamp_surf= 1;
-                               sfac= data->dist / dist;
+                               if (dist != 0.0f) sfac= data->dist / dist;
                        }
                }
                
@@ -3336,8 +3325,7 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *
                                break;
                        case 1: /* rotation (convert to degrees first) */
                                mat4_to_eulO(dvec, cob->rotOrder, ct->matrix);
-                               for (i=0; i<3; i++)
-                                       dvec[i] = (float)(dvec[i] / M_PI * 180);
+                               mul_v3_fl(dvec, (float)(180.0/M_PI)); /* rad -> deg */
                                break;
                        default: /* location */
                                copy_v3_v3(dvec, ct->matrix[3]);
@@ -3387,7 +3375,7 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *
                                        eul[i]= tmin + (sval[(int)data->map[i]] * (tmax - tmin)); 
                                        
                                        /* now convert final value back to radians */
-                                       eul[i] = (float)(eul[i] / 180 * M_PI);
+                                       eul[i] = DEG2RADF(eul[i]);
                                }
                                break;
                        default: /* location */
@@ -4022,7 +4010,9 @@ bConstraintTypeInfo *constraint_get_typeinfo (bConstraint *con)
  
 /* ---------- Data Management ------- */
 
-/* Free data of a specific constraint if it has any info */
+/* Free data of a specific constraint if it has any info.
+ * be sure to run BIK_clear_data() when freeing an IK constraint,
+ * unless DAG_scene_sort is called. */
 void free_constraint_data (bConstraint *con)
 {
        if (con->data) {
@@ -4428,6 +4418,34 @@ void get_constraint_target_matrix (struct Scene *scene, bConstraint *con, int n,
                unit_m4(mat);
        }
 }
+
+/* Get the list of targets required for solving a constraint */
+void get_constraint_targets_for_solving (bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
+{
+       bConstraintTypeInfo *cti= constraint_get_typeinfo(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 initialise as identity matrix 
+                */
+               if (cti->get_target_matrix) {
+                       for (ct= targets->first; ct; ct= ct->next) 
+                               cti->get_target_matrix(con, cob, ct, ctime);
+               }
+               else {
+                       for (ct= targets->first; ct; ct= ct->next)
+                               unit_m4(ct->matrix);
+               }
+       }
+}
  
 /* ---------- Evaluation ----------- */
 
@@ -4465,32 +4483,14 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime)
                 */
                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 */
                constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace);
-               copy_m4_m4(oldmat, cob->matrix);
                
                /* prepare targets for constraint solving */
-               if (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 initialise as identity matrix 
-                        */
-                       if (cti->get_target_matrix) {
-                               for (ct= targets.first; ct; ct= ct->next) 
-                                       cti->get_target_matrix(con, cob, ct, ctime);
-                       }
-                       else {
-                               for (ct= targets.first; ct; ct= ct->next)
-                                       unit_m4(ct->matrix);
-                       }
-               }
+               get_constraint_targets_for_solving(con, cob, &targets, ctime);
                
                /* Solve the constraint and put result in cob->matrix */
                cti->evaluate_constraint(con, cob, &targets);
@@ -4503,16 +4503,20 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime)
                        cti->flush_constraint_targets(con, &targets, 1);
                }
                
-               /* Interpolate the enforcement, to blend result of constraint into final owner transform */
+               /* move owner back into worldspace for next constraint/other business */
+               if ((con->flag & CONSTRAINT_SPACEONCE) == 0) 
+                       constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD);
+                       
+               /* 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 */
-               if (enf < 1.0) {
+               if (enf < 1.0f) {
                        float solution[4][4];
                        copy_m4_m4(solution, cob->matrix);
                        blend_m4_m4m4(cob->matrix, oldmat, solution, enf);
                }
-               
-               /* move owner back into worldspace for next constraint/other business */
-               if ((con->flag & CONSTRAINT_SPACEONCE) == 0) 
-                       constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD);
        }
 }