A few related bug-fixes/refinements
authorChris Want <cwant@ualberta.ca>
Sun, 4 Jan 2004 03:39:06 +0000 (03:39 +0000)
committerChris Want <cwant@ualberta.ca>
Sun, 4 Jan 2004 03:39:06 +0000 (03:39 +0000)
  * A patch to make sure that constraints on bones that point to
    external objects are evaluated correctly (and that the bones that
    depend on these bones are evaluated correctly, etc, ad nauseum).
    This addresses some of intrr's issues (the blender-related ones,
    that is).

  * Make sure that deformed displists are updated when the user
    manipulates any of the constraint buttons.

  * Added a nice little function, ik_chain_looper(), that executes a
    callback for every bone in an IK chain.

source/blender/include/BIF_editarmature.h
source/blender/makesdna/DNA_object_types.h
source/blender/src/buttons_object.c
source/blender/src/editarmature.c
source/blender/src/editobject.c

index 5d40f71b8510f6c06d8c06462798c609b5bb806f..df6d74cd0362b5e5892a5dc8de50b2dfc5c4ece5 100644 (file)
@@ -119,7 +119,8 @@ void show_all_pose_bones(void);
 
 int bone_looper(Object *ob, struct Bone *bone, void *data,
                                int (*bone_func)(Object *, struct Bone *, void *));
-
+int ik_chain_looper(Object *ob, struct Bone *bone, void *data,
+                                  int (*bone_func)(Object *, struct Bone *, void *));
 int is_delay_deform(void);
 
 #define        BONESEL_TIP             0x08000000
index 32be260b4501a03c4f2391ce0e71680668a4e5cf..c5fa7aeafd5053a1bdec157e5cfab3541d0f12fb 100644 (file)
@@ -176,6 +176,11 @@ extern Object workob;
 /* used many places... should be specialized */
 #define SELECT                 1
 #define ACTIVE                 2
+#define GONNA_MOVE     32 /* temporary, for figuring what stuff needs
+                                                  * updating during transform due to parenting
+                                                  * or constraints... do not rely on this value
+                                                  * unless you are me (CW).
+                                                  */
 
 /* type */
 #define OB_EMPTY               0
index 54afa9caf66cd797cd68a356489b0f6bb2f5c2bb..393131b4b6b54f66e7499558514e696e7612b248 100644 (file)
@@ -731,8 +731,6 @@ static uiBlock *add_constraintmenu(void *arg_unused)
 
 void do_constraintbuts(unsigned short event)
 {
-       clear_object_constraint_status(OBACT);
-
        switch(event) {
        case B_CONSTRAINT_CHANGENAME:
                break;
@@ -860,6 +858,9 @@ void do_constraintbuts(unsigned short event)
        default:
                break;
        }
+
+       clear_object_constraint_status(OBACT);
+       make_displists_by_armature (OBACT);
 }
 
 static void object_panel_constraint(void)
index 0b8e96bd85896f811531dc44fb88a30120e9d707..dcfd2f6838a88611fc6797606d8611db7cb423af 100644 (file)
@@ -2508,6 +2508,43 @@ int bone_looper(Object *ob, Bone *bone, void *data,
     return count;
 }
 
+int ik_chain_looper(Object *ob, Bone *bone, void *data,
+                                  int (*bone_func)(Object *, Bone *, void *)) {
+
+    /* We want to apply the function bone_func to every bone 
+     * in an ik chain -- feed ikchain_looper a bone in the chain and 
+     * a pointer to the bone_func and watch it go!. The int count 
+     * can be useful for counting bones with a certain property
+     * (e.g. skinnable)
+     */
+       Bone *curBone;
+    int   count = 0;
+
+    if (bone) {
+
+        /* This bone */
+        count += bone_func(ob, bone, data);
+
+        /* The parents */
+               for (curBone = bone; curBone; curBone=curBone->parent) {
+                       if (!curBone->parent)
+                               break;
+                       else if (!(curBone->flag & BONE_IK_TOPARENT))
+                               break;
+                       count += bone_func(ob, curBone->parent, data);
+               }
+
+               /* The children */
+               for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
+                       if (curBone->flag & BONE_IK_TOPARENT) {
+                               count += bone_func(ob, curBone, data);
+                       }
+               }
+    }
+
+    return count;
+}
+
 int bone_skinnable(Object *ob, Bone *bone, void *data)
 {
     /* Bones that are not of boneclass BONE_UNSKINNABLE
index 9ebd3898e20515457c4e662df293da09f818a776..398ae297a4a4e8f52540980714ddde19e4fa278c 100644 (file)
@@ -2638,37 +2638,6 @@ static int is_ob_constraint_target(Object *ob, ListBase *conlist) {
 
 }
 
-static int pose_do_update_flag(Object *ob) {
-       /* Figure out which pose channels need constant updating.
-        */
-       Base *base;
-       bPoseChannel *chan;
-       int do_update = 0;
-
-       if (ob->pose) {
-               for (chan = ob->pose->chanbase.first; chan; chan=chan->next){
-                       if (chan->constraints.first) {
-                               for (base= FIRSTBASE; base; base= base->next) {
-                                       if (is_ob_constraint_target(base->object, 
-                                                                                               &chan->constraints)) {
-                                               if( (base->flag & SELECT) || (ob->flag & SELECT)) {
-                                                       /* If this armature is selected, or if the
-                                                        * object that is the target of a constraint
-                                                        * is selected, then lets constantly update
-                                                        * this pose channel.
-                                                        */
-                                                       chan->flag |= PCHAN_TRANS_UPDATE;
-                                                       do_update = 1;
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-
-       return do_update;
-}
-
 int clear_bone_nocalc(Object *ob, Bone *bone, void *ptr) {
        /* When we aren't transform()-ing, we'll want to turn off
         * the no calc flag for bone bone in case the frame changes,
@@ -2737,31 +2706,6 @@ static int is_ik_root_docalc(Bone *bone) {
        return 0;
 }
 
-static void ik_chain_docalc(Bone *bone) {
-       /* Let's clear the no calc flag for an entire IK chain
-        */
-       Bone            *curBone;
-
-       /* This bone */
-       bone->flag &= ~BONE_NOCALC;
-
-       /* The parents */
-       for (curBone = bone; curBone; curBone=curBone->parent) {
-               if (!curBone->parent)
-                       break;
-               else if (!(curBone->flag & BONE_IK_TOPARENT))
-                       break;
-               curBone->parent->flag &= ~BONE_NOCALC;
-       }
-
-       /* The children */
-       for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
-               if (curBone->flag & BONE_IK_TOPARENT) {
-                       curBone->flag &= ~BONE_NOCALC;
-               }
-       }
-}
-
 static void figure_bone_nocalc_constraint(Bone *conbone, bConstraint *con,
                                                                                  Object *ob, bArmature *arm) {
        /* If this bone has a constraint with a subtarget that has
@@ -2782,14 +2726,16 @@ static void figure_bone_nocalc_constraint(Bone *conbone, bConstraint *con,
                if ( (subtarbone = get_named_bone(arm, subtar)) ) {
                        if (~subtarbone->flag & BONE_NOCALC) {
                                if (con->type == CONSTRAINT_TYPE_KINEMATIC)
-                                       ik_chain_docalc(conbone);
+                                       ik_chain_looper(ob, conbone, NULL, 
+                                                                       clear_bone_nocalc);
                                else 
                                        conbone->flag &= ~BONE_NOCALC;
                        }
                        else {
                                if (is_ik_root_docalc(conbone)) {
                                        if (con->type == CONSTRAINT_TYPE_KINEMATIC)
-                                               ik_chain_docalc(conbone);
+                                               ik_chain_looper(ob, conbone, NULL, 
+                                                                               clear_bone_nocalc);
                                        else
                                                conbone->flag &= ~BONE_NOCALC;
                                }
@@ -2800,7 +2746,8 @@ static void figure_bone_nocalc_constraint(Bone *conbone, bConstraint *con,
                /* no subtarget ... target is regular object */
                if (is_ik_root_docalc(conbone)) {
                        if (con->type == CONSTRAINT_TYPE_KINEMATIC)
-                               ik_chain_docalc(conbone);
+                               ik_chain_looper(ob, conbone, NULL, 
+                                                               clear_bone_nocalc);
                        else
                                conbone->flag &= ~BONE_NOCALC;
                }
@@ -2808,28 +2755,17 @@ static void figure_bone_nocalc_constraint(Bone *conbone, bConstraint *con,
 
 }
 
-static void figure_bone_nocalc(Object *ob) {
+static void figure_bone_nocalc_core(Object *ob, bArmature *arm) {
        /* Let's figure out which bones need to be recalculated,
         * and which don't. Calculations are based on which bones
         * are selected, and the constraints that love them.
         */
-       bArmature *arm;
        bPoseChannel *chan;
        bConstraint *con;
        Bone *conbone;
 
        int numbones, oldnumbones, iterations;
 
-       arm = get_armature(ob);
-       if (!arm) return;
-
-       if (arm->flag & ARM_RESTPOS) return;
-
-       /* Set no calc for all bones
-        */
-       bone_looper(ob, arm->bonebase.first, NULL, 
-                               set_bone_nocalc);
-
        oldnumbones = -1;
        numbones    =  0;
        iterations  =  0;
@@ -2862,6 +2798,160 @@ static void figure_bone_nocalc(Object *ob) {
        }
 }
 
+static void figure_bone_nocalc(Object *ob) {
+       /* Let's figure out which bones need to be recalculated,
+        * and which don't. Calculations are based on which bones
+        * are selected, and the constraints that love them.
+        */
+       bArmature *arm;
+
+       arm = get_armature(ob);
+       if (!arm) return;
+
+       if (arm->flag & ARM_RESTPOS) return;
+
+       /* Set no calc for all bones
+        */
+       bone_looper(ob, arm->bonebase.first, NULL, 
+                               set_bone_nocalc);
+
+       figure_bone_nocalc_core(ob, arm);
+}
+
+int bone_nocalc2chan_trans_update(Object *ob, Bone *bone, void *ptr) {
+       /* Set PCHAN_TRANS_UPDATE for channels with bones that don't have
+        * the no calc flag set ... I hate this.
+        */
+       bPoseChannel *chan;
+
+       if (~bone->flag & BONE_NOCALC) {
+               chan = get_pose_channel(ob->pose, bone->name);
+               if (chan) chan->flag |= PCHAN_TRANS_UPDATE;
+       }
+       else {
+               /* reset this thing too */
+               bone->flag &= ~BONE_NOCALC;
+       }
+       
+       return 0;
+}
+
+void clear_gonna_move(void) {
+       Base *base;
+
+       /* clear the gonna move flag */
+       for (base= FIRSTBASE; base; base= base->next) {
+               base->object->flag &= ~GONNA_MOVE;
+       }
+}
+
+int is_parent_gonna_move(Object *ob) {
+       if ( (ob->parent) &&
+                (ob->parent->flag & GONNA_MOVE) ) {
+               return 1;
+       }
+       return 0;
+}
+
+int is_constraint_target_gonna_move(Object *ob) {
+       Object *tarOb;
+       bConstraint *con;
+
+       for (con = ob->constraints.first; con; con=con->next) {
+               if ( (tarOb = get_con_target(con)) ) {
+                       if (tarOb->flag & GONNA_MOVE )
+                               return 1;
+               }
+       }
+       return 0;
+}
+
+void flag_moving_objects(void) {
+       Base *base;
+       int numgonnamove = 0, oldnumgonnamove = -1;
+
+       clear_gonna_move();
+
+       /* the 'well ordering principle' guarantees convergence (honest)
+        */
+       while (numgonnamove != oldnumgonnamove) {
+               oldnumgonnamove = numgonnamove;
+               numgonnamove = 0;
+               for (base= FIRSTBASE; base; base= base->next) {
+                       if (base->object->flag & GONNA_MOVE) {
+                               ++numgonnamove;
+                       }
+                       else if (base->flag & SELECT) {
+                               base->object->flag |= GONNA_MOVE;
+                               ++numgonnamove;
+                       }
+                       else if (is_parent_gonna_move(base->object)) {
+                               base->object->flag |= GONNA_MOVE;
+                               ++numgonnamove;
+                       }
+                       else if (is_constraint_target_gonna_move(base->object)) {
+                               base->object->flag |= GONNA_MOVE;
+                               ++numgonnamove;
+                       }
+               }
+       }
+
+}
+
+static int pose_do_update_flag(Object *ob) {
+       /* Figure out which pose channels need constant updating.
+        * Well use the bone BONE_NOCALC bit to do some temporary
+        * flagging (so we can reuse code), which will later be
+        * converted to a value for a channel... I hate this.
+        */
+       Base *base;
+       bPoseChannel *chan;
+       int do_update = 0;
+       bArmature *arm;
+
+       arm = get_armature(ob);
+       if (!arm) return 0;
+
+       /* initialize */
+       bone_looper(ob, arm->bonebase.first, NULL, 
+                               set_bone_nocalc);
+
+       if (ob->pose) {
+               for (chan = ob->pose->chanbase.first; chan; chan=chan->next){
+                       if (chan->constraints.first) {
+                               for (base= FIRSTBASE; base; base= base->next) {
+                                       if (is_ob_constraint_target(base->object, 
+                                                                                               &chan->constraints)) {
+                                               if( (base->object->flag & GONNA_MOVE) || 
+                                                       (ob->flag & GONNA_MOVE)) {
+                                                       Bone *bone;
+                                                       /* If this armature is selected, or if the
+                                                        * object that is the target of a constraint
+                                                        * is selected, then lets constantly update
+                                                        * this pose channel.
+                                                        */
+                                                       bone = get_named_bone(ob->data, chan->name);
+                                                       if (bone) {
+                                                               bone->flag &= ~BONE_NOCALC;
+                                                               ++do_update;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if (do_update) {
+               figure_bone_nocalc_core(ob, arm);
+       }
+
+       bone_looper(ob, arm->bonebase.first, NULL, 
+                               bone_nocalc2chan_trans_update);
+
+       return do_update;
+}
+
 /*** POSE FIGURIN' -- END ***/
 
 
@@ -2878,6 +2968,8 @@ static void setbaseflags_for_editing(int mode)    /* 0,'g','r','s' */
        Base *base;
        
        copy_baseflags();
+       flag_moving_objects();
+
 
        for (base= FIRSTBASE; base; base= base->next) {
                base->flag &= ~(BA_PARSEL+BA_WASSEL);