Armature speed ups, Part III
authorChris Want <cwant@ualberta.ca>
Sat, 3 Jan 2004 03:53:18 +0000 (03:53 +0000)
committerChris Want <cwant@ualberta.ca>
Sat, 3 Jan 2004 03:53:18 +0000 (03:53 +0000)
----------------------------

Another (major) armature speed up for bones with many constraints.

When tranform()-ing, figure out which bones need to be recalculated
beforehand and only update those bones.

source/blender/blenkernel/intern/armature.c
source/blender/include/BIF_editconstraint.h
source/blender/makesdna/DNA_armature_types.h
source/blender/src/buttons_editing.c
source/blender/src/editconstraint.c
source/blender/src/editobject.c

index e5f57e2e213e54b071ca4f7b010da907991c0ef3..b16d2143edf1eb741714b3872ba332b7c1168d13 100644 (file)
@@ -297,11 +297,6 @@ void where_is_bone1_time (Object *ob, Bone *bone, float ctime)
                        where_is_bone_time (ob, bone->parent, ctime);
        }
 
-       /* Build the parent matrix : Depreciated */
-//     if (bone->parent)
-//             Mat4MulMat4(bone->parmat, bone->parent->obmat, bone->parent->parmat);
-//     else
-//             Mat4One (bone->parmat);
 #endif
 
        if (arm){
@@ -312,6 +307,13 @@ void where_is_bone1_time (Object *ob, Bone *bone, float ctime)
                }
        }
 
+       /* If the bone has been flagged as 'no calc', let's not
+        * bother calculating it.
+        */
+       if (bone->flag & BONE_NOCALC) {
+               return;
+       }
+
        if (bone->flag & BONE_IK_TOPARENT){
                bone->loc[0]=bone->loc[1]=bone->loc[2]=0.0F;
        }
@@ -839,8 +841,10 @@ static void apply_pose_bonechildren (Bone* bone, bPose* pose, int doit)
        // Ensure there is a channel for this bone 
        chan = verify_pose_channel (pose, bone->name);
 
-       if (chan) {
-       // Search the pose for a channel with the same name 
+       /* Only do this crazy stuff if the no calc flag
+        * is cleared for this bone.
+        */
+       if (chan && (~bone->flag & BONE_NOCALC)) {
                if (chan->flag & POSE_LOC) 
                        memcpy (bone->loc, chan->loc, sizeof (bone->loc));
                if (chan->flag & POSE_SIZE) 
index 963b9fb4e084443f472e71ea084a31f4449f3650..0c7742323c03d1a0191b1e3bacf802be6d58adea 100644 (file)
@@ -56,6 +56,9 @@ struct ListBase *get_constraint_client_channels (int forcevalid);
 struct ListBase *get_constraint_client(char *name, short *clienttype, void** clientdata);
 int test_constraints (struct Object *owner, const char *substring, int disable);
 void test_scene_constraints (void);
+
+char *get_con_subtarget_name(struct bConstraint *constraint, 
+                                                        struct Object *target);
 struct Object *get_con_target(struct bConstraint *constraint);
 
 #endif
index b808249ace0c3eb222305cef17ccdb8e69e9a21a..5124716bc51da555975183f5d3868f3ff7829f04 100644 (file)
@@ -110,7 +110,11 @@ enum {
                BONE_DONE               =       0x00000080,     /* For detecting cyclic dependancies */
 
                BONE_ISEMPTY    =       0x00000100,
-               BONE_ISMUSCLE   =       0x00000200
+               BONE_ISMUSCLE   =       0x00000200,
+               BONE_NOCALC     =   0x00000400 /* Don't calculate bone 
+                                                                               * transformation, when flagged
+                                                                               * (note: this is a temporary flag)
+                                                                               */
 };
 
 enum {
@@ -122,7 +126,8 @@ enum {
                BONE_QUATROTBIT,
                BONE_HIDDENBIT,
                BONE_ISEMPTYBIT,
-               BONE_ISMUSCLEBIT
+               BONE_ISMUSCLEBIT,
+               BONE_NOCALCBIT
 };
 
 enum {
index 22d17f43c192dae7b5428a40f9052bf912bb195c..915f4ef456e9285ddcf18b155b0f18f11a21adcf 100644 (file)
@@ -1318,16 +1318,25 @@ static void validate_editbonebutton_cb(void *bonev, void *arg2_unused)
        validate_editbonebutton(curBone);
 }
 
+static void armature_rest_pos_func(void *notused1, void *notused2) {
+       clear_object_constraint_status(OBACT);
+       make_displists_by_armature(OBACT);
+}
 
 static void editing_panel_armature_type(Object *ob, bArmature *arm)
 {
        uiBlock         *block;
+       uiBut       *but;
        int                     bx=148, by=100;
 
        block= uiNewBlock(&curarea->uiblocks, "editing_panel_armature_type", UI_EMBOSS, UI_HELV, curarea->win);
        if(uiNewPanel(curarea, block, "Armature", "Editing", 320, 0, 318, 204)==0) return;
        
-       uiDefButI(block, TOG|BIT|ARM_RESTPOSBIT,REDRAWVIEW3D, "Rest Pos", bx,by,97,20, &arm->flag, 0, 0, 0, 0, "Disable all animation for this object");
+       but = uiDefButI(block, TOG|BIT|ARM_RESTPOSBIT,REDRAWVIEW3D, 
+                                       "Rest Pos", bx,by,97,20, &arm->flag, 0, 0, 0, 0, 
+                                       "Disable all animation for this object");
+       uiButSetFunc(but, armature_rest_pos_func, NULL, NULL);
+
        uiBlockBeginAlign(block);
        uiDefButI(block, TOG|BIT|ARM_DRAWAXESBIT,REDRAWVIEW3D, "Draw Axes", bx,by-46,97,20, &arm->flag, 0, 0, 0, 0, "Draw bone axes");
        uiDefButI(block, TOG|BIT|ARM_DRAWNAMESBIT,REDRAWVIEW3D, "Draw Names", bx,by-69,97,20, &arm->flag, 0, 0, 0, 0, "Draw bone names");
index be74c04507490d19b005e022e513ed1f4a43efb6..571eb2b8eb4e6e921d8ea23d0580d82db38857f4 100644 (file)
@@ -774,6 +774,66 @@ void add_influence_key_to_constraint (bConstraint *con){
        printf("doesn't do anything yet\n");
 }
 
+char *get_con_subtarget_name(bConstraint *constraint, Object *target)
+{
+       /*
+        * If the target for this constraint is target, return a pointer 
+        * to the name for this constraints subtarget ... NULL otherwise
+        */
+       switch (constraint->type) {
+
+               case CONSTRAINT_TYPE_ACTION:
+               {
+                       bActionConstraint *data = constraint->data;
+                       if (data->tar==target) return data->subtarget;
+               }
+               break;
+               case CONSTRAINT_TYPE_LOCLIKE:
+               {
+                       bLocateLikeConstraint *data = constraint->data;
+                       if (data->tar==target) return data->subtarget;
+               }
+               break;
+               case CONSTRAINT_TYPE_ROTLIKE:
+               {
+                       bRotateLikeConstraint *data = constraint->data;
+                       if (data->tar==target) return data->subtarget;
+               }
+               break;
+               case CONSTRAINT_TYPE_KINEMATIC:
+               {
+                       bKinematicConstraint *data = constraint->data;
+                       if (data->tar==target) return data->subtarget;
+               }
+               break;
+               case CONSTRAINT_TYPE_TRACKTO:
+               {
+                       bTrackToConstraint *data = constraint->data;
+                       if (data->tar==target) return data->subtarget;
+               }
+               break;
+               case CONSTRAINT_TYPE_LOCKTRACK:
+               {
+                       bLockTrackConstraint *data = constraint->data;
+                       if (data->tar==target) return data->subtarget;
+               }
+               break;
+               case CONSTRAINT_TYPE_FOLLOWPATH: 
+                       /* wonder if this is relevent, since this constraint 
+                        * cannot have a subtarget - theeth 
+                        */
+               {
+                       /*
+                        * bFollowPathConstraint *data = constraint->data;
+                        */
+                       return NULL;
+               }
+               break;
+       }
+       
+       return NULL;  
+}
+
 Object *get_con_target(bConstraint *constraint)
 {
        /*
index 64359091ef5516ed054c942297c151bacb84d308..14221e8f84046a49b5217899732be12b2dc097a6 100644 (file)
@@ -2669,6 +2669,199 @@ static int pose_do_update_flag(Object *ob) {
        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,
+        * or something
+        */
+       bone->flag &= ~BONE_NOCALC;
+       
+       return 0;
+}
+
+
+static void clear_bone_nocalc_ob(Object *ob) {
+       /* Let's clear no calc for all of the bones in the whole darn armature
+        */
+       bArmature *arm;
+       arm = get_armature(ob);
+       if (arm) {
+               bone_looper(ob, arm->bonebase.first, NULL, 
+                                       clear_bone_nocalc);
+       }
+
+}
+
+int set_bone_nocalc(Object *ob, Bone *bone, void *ptr) {
+       /* Calculating bone transformation makes thins slow ...
+        * lets set the no calc flag for a bone by default
+        */
+       bone->flag |= BONE_NOCALC;
+       
+       return 0;
+}
+
+int selected_bone_docalc(Object *ob, Bone *bone, void *ptr) {
+       /* Let's clear the no calc flag for selected bones.
+        * This function always returns 1 for non-no calc bones
+        * (a.k.a., the 'do calc' bones) so that the bone_looper 
+        * will count these
+        */
+       if (bone->flag & BONE_NOCALC) {
+               if ( (bone->flag & BONE_SELECTED) ) {
+                       bone->flag &= ~BONE_NOCALC;
+                       return 1;
+               }
+               
+       }
+       else {
+               return 1;
+       }
+       return 0;
+}
+
+static int is_ik_root_docalc(Bone *bone) {
+       Bone            *rootBone;
+
+       /* The parents */
+       for (rootBone = bone; rootBone; rootBone=rootBone->parent) {
+               if (!rootBone->parent)
+                       break;
+               else if (!(rootBone->flag & BONE_IK_TOPARENT))
+                       break;
+       }
+
+       if (~rootBone->flag & BONE_NOCALC)
+               return 1;
+
+       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
+        * the nocalc flag cleared, then we better clear the no calc flag
+        * on this bone too (and the whole IK chain if this is an IK
+        * constraint).
+        *
+        * Conversly, if this bone has an IK constraint and the root of
+        * the chain has the no calc flag cleared, we had best clear that
+        * flag for the whole chain.
+        */
+       Bone *subtarbone;
+       char *subtar;
+
+       subtar = get_con_subtarget_name(con, ob);
+                                               
+       if (subtar) {
+               if ( (subtarbone = get_named_bone(arm, subtar)) ) {
+                       if (~subtarbone->flag & BONE_NOCALC) {
+                               if (con->type == CONSTRAINT_TYPE_KINEMATIC)
+                                       ik_chain_docalc(conbone);
+                               else 
+                                       conbone->flag &= ~BONE_NOCALC;
+                       }
+                       else {
+                               if (is_ik_root_docalc(conbone)) {
+                                       if (con->type == CONSTRAINT_TYPE_KINEMATIC)
+                                               ik_chain_docalc(conbone);
+                                       else
+                                               conbone->flag &= ~BONE_NOCALC;
+                               }
+                       }
+               }
+       }
+       else {
+               /* no subtarget ... target is regular object */
+               if (is_ik_root_docalc(conbone)) {
+                       if (con->type == CONSTRAINT_TYPE_KINEMATIC)
+                               ik_chain_docalc(conbone);
+                       else
+                               conbone->flag &= ~BONE_NOCALC;
+               }
+       }
+
+}
+
+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;
+       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;
+
+       /* O.K., lets loop until we don't clear any more no calc bones
+        */
+       while (oldnumbones != numbones) {
+               /* I wonder if this will ever get executed? */
+               if ( (++iterations) == 1000) {
+                       printf("figurin' nocalc is talking too long\n");
+                       break;
+               }
+
+               oldnumbones = numbones;
+
+               /* clear no calc for selected bones and count */
+               numbones = bone_looper(ob, arm->bonebase.first, NULL, 
+                                                          selected_bone_docalc);
+
+               if (ob->pose) {
+                       for (chan = ob->pose->chanbase.first; chan; chan=chan->next){
+                               conbone = get_named_bone(arm, chan->name);
+                               if (conbone) {
+                                       for (con = chan->constraints.first; con; con=con->next) {
+                                               figure_bone_nocalc_constraint(conbone, con, ob, arm);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
 /*** POSE FIGURIN' -- END ***/
 
 
@@ -3430,6 +3623,12 @@ void special_aftertrans_update(char mode, int flip, short canceled, int keyflags
                bPose   *pose;
                bPoseChannel *pchan;
 
+               /* we had better clear the no calc flags on the bones
+                * ... else things won't look too good when changing
+                * frames, etc.
+                */
+               clear_bone_nocalc_ob(G.obpose);
+
                if (U.uiflag & KEYINSERTACT && !canceled){
                        act=G.obpose->action;
                        pose=G.obpose->pose;
@@ -4144,6 +4343,8 @@ void transform(int mode)
 
                switch (G.obpose->type) {
                case OB_ARMATURE:
+                       /* figure out which bones need calculating */
+                       figure_bone_nocalc(G.obpose);
                        make_trans_bones(mode);
                        break;
                }