A few related bug-fixes/refinements

* 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.
This commit is contained in:
Chris Want
2004-01-04 03:39:06 +00:00
parent f6d24b4a80
commit 9f009558bf
5 changed files with 210 additions and 74 deletions

View File

@@ -119,7 +119,8 @@ void show_all_pose_bones(void);
int bone_looper(Object *ob, struct Bone *bone, void *data, int bone_looper(Object *ob, struct Bone *bone, void *data,
int (*bone_func)(Object *, struct Bone *, void *)); 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); int is_delay_deform(void);
#define BONESEL_TIP 0x08000000 #define BONESEL_TIP 0x08000000

View File

@@ -176,6 +176,11 @@ extern Object workob;
/* used many places... should be specialized */ /* used many places... should be specialized */
#define SELECT 1 #define SELECT 1
#define ACTIVE 2 #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 */ /* type */
#define OB_EMPTY 0 #define OB_EMPTY 0

View File

@@ -731,8 +731,6 @@ static uiBlock *add_constraintmenu(void *arg_unused)
void do_constraintbuts(unsigned short event) void do_constraintbuts(unsigned short event)
{ {
clear_object_constraint_status(OBACT);
switch(event) { switch(event) {
case B_CONSTRAINT_CHANGENAME: case B_CONSTRAINT_CHANGENAME:
break; break;
@@ -860,6 +858,9 @@ void do_constraintbuts(unsigned short event)
default: default:
break; break;
} }
clear_object_constraint_status(OBACT);
make_displists_by_armature (OBACT);
} }
static void object_panel_constraint(void) static void object_panel_constraint(void)

View File

@@ -2508,6 +2508,43 @@ int bone_looper(Object *ob, Bone *bone, void *data,
return count; 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) int bone_skinnable(Object *ob, Bone *bone, void *data)
{ {
/* Bones that are not of boneclass BONE_UNSKINNABLE /* Bones that are not of boneclass BONE_UNSKINNABLE

View 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) { int clear_bone_nocalc(Object *ob, Bone *bone, void *ptr) {
/* When we aren't transform()-ing, we'll want to turn off /* When we aren't transform()-ing, we'll want to turn off
* the no calc flag for bone bone in case the frame changes, * 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; 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, static void figure_bone_nocalc_constraint(Bone *conbone, bConstraint *con,
Object *ob, bArmature *arm) { Object *ob, bArmature *arm) {
/* If this bone has a constraint with a subtarget that has /* 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 = get_named_bone(arm, subtar)) ) {
if (~subtarbone->flag & BONE_NOCALC) { if (~subtarbone->flag & BONE_NOCALC) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC) if (con->type == CONSTRAINT_TYPE_KINEMATIC)
ik_chain_docalc(conbone); ik_chain_looper(ob, conbone, NULL,
clear_bone_nocalc);
else else
conbone->flag &= ~BONE_NOCALC; conbone->flag &= ~BONE_NOCALC;
} }
else { else {
if (is_ik_root_docalc(conbone)) { if (is_ik_root_docalc(conbone)) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC) if (con->type == CONSTRAINT_TYPE_KINEMATIC)
ik_chain_docalc(conbone); ik_chain_looper(ob, conbone, NULL,
clear_bone_nocalc);
else else
conbone->flag &= ~BONE_NOCALC; conbone->flag &= ~BONE_NOCALC;
} }
@@ -2800,7 +2746,8 @@ static void figure_bone_nocalc_constraint(Bone *conbone, bConstraint *con,
/* no subtarget ... target is regular object */ /* no subtarget ... target is regular object */
if (is_ik_root_docalc(conbone)) { if (is_ik_root_docalc(conbone)) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC) if (con->type == CONSTRAINT_TYPE_KINEMATIC)
ik_chain_docalc(conbone); ik_chain_looper(ob, conbone, NULL,
clear_bone_nocalc);
else else
conbone->flag &= ~BONE_NOCALC; 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, /* Let's figure out which bones need to be recalculated,
* and which don't. Calculations are based on which bones * and which don't. Calculations are based on which bones
* are selected, and the constraints that love them. * are selected, and the constraints that love them.
*/ */
bArmature *arm;
bPoseChannel *chan; bPoseChannel *chan;
bConstraint *con; bConstraint *con;
Bone *conbone; Bone *conbone;
int numbones, oldnumbones, iterations; 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; oldnumbones = -1;
numbones = 0; numbones = 0;
iterations = 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 ***/ /*** POSE FIGURIN' -- END ***/
@@ -2878,6 +2968,8 @@ static void setbaseflags_for_editing(int mode) /* 0,'g','r','s' */
Base *base; Base *base;
copy_baseflags(); copy_baseflags();
flag_moving_objects();
for (base= FIRSTBASE; base; base= base->next) { for (base= FIRSTBASE; base; base= base->next) {
base->flag &= ~(BA_PARSEL+BA_WASSEL); base->flag &= ~(BA_PARSEL+BA_WASSEL);