From d311e9617468beb507202e4c92017703bc11feb3 Mon Sep 17 00:00:00 2001 From: Chris Want Date: Sat, 3 Jan 2004 03:53:18 +0000 Subject: Armature speed ups, Part III ---------------------------- 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 | 18 ++- source/blender/include/BIF_editconstraint.h | 3 + source/blender/makesdna/DNA_armature_types.h | 9 +- source/blender/src/buttons_editing.c | 11 +- source/blender/src/editconstraint.c | 60 ++++++++ source/blender/src/editobject.c | 201 +++++++++++++++++++++++++++ 6 files changed, 292 insertions(+), 10 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index e5f57e2e213..b16d2143edf 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -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) diff --git a/source/blender/include/BIF_editconstraint.h b/source/blender/include/BIF_editconstraint.h index 963b9fb4e08..0c7742323c0 100644 --- a/source/blender/include/BIF_editconstraint.h +++ b/source/blender/include/BIF_editconstraint.h @@ -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 diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index b808249ace0..5124716bc51 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -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 { diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 22d17f43c19..915f4ef456e 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -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"); diff --git a/source/blender/src/editconstraint.c b/source/blender/src/editconstraint.c index be74c045074..571eb2b8eb4 100644 --- a/source/blender/src/editconstraint.c +++ b/source/blender/src/editconstraint.c @@ -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) { /* diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index 64359091ef5..14221e8f840 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -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; } -- cgit v1.2.3