diff options
author | Chris Want <cwant@ualberta.ca> | 2004-01-03 06:53:18 +0300 |
---|---|---|
committer | Chris Want <cwant@ualberta.ca> | 2004-01-03 06:53:18 +0300 |
commit | d311e9617468beb507202e4c92017703bc11feb3 (patch) | |
tree | d4ab64d160b682e31e55cdd4d827faa0effa9576 /source/blender/src | |
parent | de21846e690dd5a4606a42b776d55f119e5620d7 (diff) |
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.
Diffstat (limited to 'source/blender/src')
-rw-r--r-- | source/blender/src/buttons_editing.c | 11 | ||||
-rw-r--r-- | source/blender/src/editconstraint.c | 60 | ||||
-rw-r--r-- | source/blender/src/editobject.c | 201 |
3 files changed, 271 insertions, 1 deletions
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; } |