Attempted bugfix to improve behaviour of inverse calculations for ChildOf
[blender.git] / source / blender / editors / object / object_constraint.c
index 3c84b2df1d2b61730880cf5d4610e3342f0b428a..40d52e0b2618e32a7777534186121c566a5d976a 100644 (file)
@@ -691,6 +691,7 @@ static int childof_set_inverse_exec (bContext *C, wmOperator *op)
        Object *ob = ED_object_active_context(C);
        bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF);
        bChildOfConstraint *data= (con) ? (bChildOfConstraint *)con->data : NULL;
+       bConstraint *lastcon = NULL;
        bPoseChannel *pchan= NULL;
        
        /* despite 3 layers of checks, we may still not be able to find a constraint */
@@ -703,27 +704,45 @@ static int childof_set_inverse_exec (bContext *C, wmOperator *op)
        /* nullify inverse matrix first */
        unit_m4(data->invmat);
        
-       /* try to find a pose channel */
+       /* try to find a pose channel - assume that this is the constraint owner */
        // TODO: get from context instead?
        if (ob && ob->pose)
                pchan= get_active_posechannel(ob);
        
-       /* calculate/set inverse matrix */
+       /* calculate/set inverse matrix:
+        *      We just calculate all transform-stack eval up to but not including this constraint.
+        *      This is because inverse should just inverse correct for just the constraint's influence
+        *      when it gets applied; that is, at the time of application, we don't know anything about
+        *      what follows.
+        */
        if (pchan) {
-               float pmat[4][4], cinf;
                float imat[4][4], tmat[4][4];
+               float pmat[4][4];
                
-               /* make copy of pchan's original pose-mat (for use later) */
+               /* 1. calculate posemat where inverse doesn't exist yet (inverse was cleared above), 
+                * to use as baseline ("pmat") to derive delta from. This extra calc saves users 
+                * from having pressing "Clear Inverse" first
+                */
+               where_is_pose(scene, ob);
                copy_m4_m4(pmat, pchan->pose_mat);
                
-               /* disable constraint for pose to be solved without it */
-               cinf= con->enforce;
-               con->enforce= 0.0f;
+               /* 2. knock out constraints starting from this one */
+               lastcon = pchan->constraints.last;
+               pchan->constraints.last = con->prev;
+               
+               if (con->prev) {
+                       /* new end must not point to this one, else this chain cutting is useless */
+                       con->prev->next = NULL;
+               }
+               else {
+                       /* constraint was first */
+                       pchan->constraints.first = NULL;
+               }
                
-               /* solve pose without constraint */
+               /* 3. solve pose without disabled constraints */
                where_is_pose(scene, ob);
                
-               /* determine effect of constraint by removing the newly calculated 
+               /* 4. determine effect of constraint by removing the newly calculated 
                 * pchan->pose_mat from the original pchan->pose_mat, thus determining 
                 * the effect of the constraint
                 */
@@ -731,8 +750,19 @@ static int childof_set_inverse_exec (bContext *C, wmOperator *op)
                mul_m4_m4m4(tmat, imat, pmat);
                invert_m4_m4(data->invmat, tmat);
                
-               /* recalculate pose with new inv-mat */
-               con->enforce= cinf;
+               /* 5. restore constraints */
+               pchan->constraints.last = lastcon;
+               
+               if (con->prev) {
+                       /* hook up prev to this one again */
+                       con->prev->next = con;
+               }
+               else {
+                       /* set as first again */
+                       pchan->constraints.first = con;
+               }
+               
+               /* 6. recalculate pose with new inv-mat applied */
                where_is_pose(scene, ob);
        }
        else if (ob) {