== Local Constraints for Proxies (Peach Request) ==
Proxy protected bones can now get local (per-file) constraints added to them, which will be preserved after a file load. This is necessary for adding constraints to proxy-protected bones for special purposes while animating (i.e. adding CopyLocs to IK-hand controls to pick up an object). These must be added after any constraints from the proxy, as proxy constraints may come and go without warning. As such, the UI forbids this from happening by removing the relevant button. I've also made UI-changes to show which constraints come from the proxy (the buttons to move the constraint up/down and delete it, are replace with two icons - a the proxy 'ghost' icon and a lock). Also, trying to change any settings of proxy-protected constraint will show an error. Notes: * Object constraints are still not playing nice with proxies yet. They didn't before this commit either...
This commit is contained in:
@@ -117,6 +117,9 @@ void copy_constraints(struct ListBase *dst, struct ListBase *src);
|
||||
void relink_constraints(struct ListBase *list);
|
||||
void free_constraint_data(struct bConstraint *con);
|
||||
|
||||
/* Constraints + Proxies function prototypes */
|
||||
void extract_proxylocal_constraints(struct ListBase *dst, struct ListBase *src);
|
||||
short proxylocked_constraints_owner(struct Object *ob, struct bPoseChannel *pchan);
|
||||
|
||||
/* Constraint Channel function prototypes */
|
||||
struct bConstraintChannel *get_constraint_channel(struct ListBase *list, const char *name);
|
||||
@@ -126,6 +129,7 @@ void copy_constraint_channels(struct ListBase *dst, struct ListBase *src);
|
||||
void clone_constraint_channels(struct ListBase *dst, struct ListBase *src);
|
||||
void free_constraint_channels(struct ListBase *chanbase);
|
||||
|
||||
|
||||
/* Constraint Evaluation function prototypes */
|
||||
struct bConstraintOb *constraints_make_evalob(struct Object *ob, void *subdata, short datatype);
|
||||
void constraints_clear_evalob(struct bConstraintOb *cob);
|
||||
|
||||
@@ -1317,6 +1317,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
|
||||
pchan= pose->chanbase.first;
|
||||
for(; pchan; pchan= pchan->next) {
|
||||
if(pchan->bone->layer & layer_protected) {
|
||||
ListBase proxylocal_constraints = {NULL, NULL};
|
||||
pchanp= get_pose_channel(frompose, pchan->name);
|
||||
|
||||
/* copy posechannel to temp, but restore important pointers */
|
||||
@@ -1327,9 +1328,16 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
|
||||
pchanw.child= pchan->child;
|
||||
pchanw.path= NULL;
|
||||
|
||||
/* constraints, set target ob pointer to own object */
|
||||
/* constraints - proxy constraints are flushed... local ones are added after
|
||||
* 1. extract constraints not from proxy (CONSTRAINT_PROXY_LOCAL) from pchan's constraints
|
||||
* 2. copy proxy-pchan's constraints on-to new
|
||||
* 3. add extracted local constraints back on top
|
||||
*/
|
||||
extract_proxylocal_constraints(&proxylocal_constraints, &pchan->constraints);
|
||||
copy_constraints(&pchanw.constraints, &pchanp->constraints);
|
||||
addlisttolist(&pchanw.constraints, &proxylocal_constraints);
|
||||
|
||||
/* constraints - set target ob pointer to own object */
|
||||
for (con= pchanw.constraints.first; con; con= con->next) {
|
||||
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
|
||||
@@ -3246,6 +3246,46 @@ void copy_constraints (ListBase *dst, ListBase *src)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- Constraints and Proxies ------- */
|
||||
|
||||
/* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL (i.e. added to bone that's proxy-synced in this file) */
|
||||
void extract_proxylocal_constraints (ListBase *dst, ListBase *src)
|
||||
{
|
||||
bConstraint *con, *next;
|
||||
|
||||
/* for each tagged constraint, remove from src and move to dst */
|
||||
for (con= src->first; con; con= next) {
|
||||
next= con->next;
|
||||
|
||||
/* check if tagged */
|
||||
if (con->flag & CONSTRAINT_PROXY_LOCAL) {
|
||||
BLI_remlink(src, con);
|
||||
BLI_addtail(dst, con);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns if the owner of the constraint is proxy-protected */
|
||||
short proxylocked_constraints_owner (Object *ob, bPoseChannel *pchan)
|
||||
{
|
||||
/* Currently, constraints can only be on object or bone level */
|
||||
if (ob && ob->proxy) {
|
||||
if (ob->pose && pchan) {
|
||||
bArmature *arm= ob->data;
|
||||
|
||||
/* On bone-level, check if bone is on proxy-protected layer */
|
||||
if ((pchan->bone) && (pchan->bone->layer & arm->layer_protected))
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
/* FIXME: constraints on object-level are not handled well yet */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------- Target-Matrix Stuff ------- */
|
||||
|
||||
/* This function is a relic from the prior implementations of the constraints system, when all
|
||||
|
||||
@@ -352,7 +352,9 @@ typedef enum B_CONSTRAINT_FLAG {
|
||||
/* to indicate that the owner's space should only be changed into ownspace, but not out of it */
|
||||
CONSTRAINT_SPACEONCE = (1<<6),
|
||||
/* influence ipo is on constraint itself, not in action channel */
|
||||
CONSTRAINT_OWN_IPO = (1<<7)
|
||||
CONSTRAINT_OWN_IPO = (1<<7),
|
||||
/* indicates that constraint was added locally (i.e. didn't come from the proxy-lib) */
|
||||
CONSTRAINT_PROXY_LOCAL = (1<<8)
|
||||
} B_CONSTRAINT_FLAG;
|
||||
|
||||
/* bConstraint->ownspace/tarspace */
|
||||
|
||||
@@ -190,15 +190,18 @@ static void constraint_active_func(void *ob_v, void *con_v)
|
||||
|
||||
static void add_constraint_to_active(Object *ob, bConstraint *con)
|
||||
{
|
||||
ListBase *list;
|
||||
ListBase *list= get_active_constraints(ob);
|
||||
bPoseChannel *pchan= get_active_posechannel(ob);
|
||||
|
||||
list = get_active_constraints(ob);
|
||||
if (list) {
|
||||
unique_constraint_name(con, list);
|
||||
BLI_addtail(list, con);
|
||||
|
||||
if (proxylocked_constraints_owner(ob, pchan))
|
||||
con->flag |= CONSTRAINT_PROXY_LOCAL;
|
||||
|
||||
con->flag |= CONSTRAINT_ACTIVE;
|
||||
for(con= con->prev; con; con= con->prev)
|
||||
for (con= con->prev; con; con= con->prev)
|
||||
con->flag &= ~CONSTRAINT_ACTIVE;
|
||||
}
|
||||
}
|
||||
@@ -209,8 +212,7 @@ static void get_constraint_ipo_context(void *ob_v, char *actname)
|
||||
{
|
||||
Object *ob= ob_v;
|
||||
|
||||
/* todo; check object if it has ob-level action ipo */
|
||||
|
||||
/* todo: check object if it has ob-level action ipo */
|
||||
if (ob->flag & OB_POSEMODE) {
|
||||
bPoseChannel *pchan;
|
||||
|
||||
@@ -503,12 +505,15 @@ static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short
|
||||
static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, short *xco, short *yco)
|
||||
{
|
||||
Object *ob= OBACT;
|
||||
bPoseChannel *pchan= get_active_posechannel(ob);
|
||||
bConstraintTypeInfo *cti;
|
||||
uiBut *but;
|
||||
char typestr[32];
|
||||
short height, width = 265;
|
||||
short proxy_protected;
|
||||
int rb_col;
|
||||
|
||||
/* get constraint typeinfo */
|
||||
cti= constraint_get_typeinfo(con);
|
||||
if (cti == NULL) {
|
||||
/* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
|
||||
@@ -520,6 +525,13 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
|
||||
else
|
||||
strcpy(typestr, cti->name);
|
||||
|
||||
/* determine whether constraint is proxy protected or not */
|
||||
if (proxylocked_constraints_owner(ob, pchan)) {
|
||||
proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
|
||||
}
|
||||
else
|
||||
proxy_protected= 0;
|
||||
|
||||
/* unless button has own callback, it adds this callback to button */
|
||||
uiBlockSetFunc(block, constraint_active_func, ob, con);
|
||||
|
||||
@@ -534,17 +546,8 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
|
||||
/* open/close */
|
||||
uiDefIconButBitS(block, ICONTOG, CONSTRAINT_EXPAND, B_CONSTRAINT_TEST, ICON_DISCLOSURE_TRI_RIGHT, *xco-10, *yco, 20, 20, &con->flag, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Constraint");
|
||||
|
||||
/* up/down */
|
||||
uiBlockBeginAlign(block);
|
||||
uiBlockSetEmboss(block, UI_EMBOSS);
|
||||
but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_UP, *xco+width-50, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint up in constraint stack");
|
||||
uiButSetFunc(but, constraint_moveUp, ob, con);
|
||||
|
||||
but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_DOWN, *xco+width-50+18, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint down in constraint stack");
|
||||
uiButSetFunc(but, constraint_moveDown, ob, con);
|
||||
uiBlockEndAlign(block);
|
||||
|
||||
if (con->flag & CONSTRAINT_EXPAND) {
|
||||
/* name */
|
||||
if ((con->flag & CONSTRAINT_EXPAND) && (proxy_protected==0)) {
|
||||
if (con->flag & CONSTRAINT_DISABLE)
|
||||
uiBlockSetCol(block, TH_REDALERT);
|
||||
|
||||
@@ -568,14 +571,60 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
|
||||
|
||||
uiBlockSetCol(block, TH_AUTO);
|
||||
|
||||
uiBlockSetEmboss(block, UI_EMBOSSN);
|
||||
/* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
|
||||
if (proxy_protected) {
|
||||
uiBlockSetEmboss(block, UI_EMBOSSN);
|
||||
|
||||
/* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
|
||||
uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, *xco+244, *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
|
||||
uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, *xco+262, *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
|
||||
|
||||
uiBlockSetEmboss(block, UI_EMBOSS);
|
||||
}
|
||||
else {
|
||||
short prev_proxylock;
|
||||
|
||||
/* Up/Down buttons:
|
||||
* Proxy-constraints are not allowed to occur after local (non-proxy) constraints
|
||||
* as that poses problems when restoring them, so disable the "up" button where
|
||||
* it may cause this situation.
|
||||
*/
|
||||
if (proxylocked_constraints_owner(ob, pchan)) {
|
||||
if (con->prev) {
|
||||
prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
|
||||
}
|
||||
else
|
||||
prev_proxylock= 0;
|
||||
}
|
||||
else
|
||||
prev_proxylock= 0;
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
uiBlockSetEmboss(block, UI_EMBOSS);
|
||||
|
||||
if (prev_proxylock == 0) {
|
||||
but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_UP, *xco+width-50, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint up in constraint stack");
|
||||
uiButSetFunc(but, constraint_moveUp, ob, con);
|
||||
}
|
||||
|
||||
but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_DOWN, *xco+width-50+18, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint down in constraint stack");
|
||||
uiButSetFunc(but, constraint_moveDown, ob, con);
|
||||
uiBlockEndAlign(block);
|
||||
|
||||
|
||||
/* Close 'button' - emboss calls here disable drawing of 'button' behind X */
|
||||
uiBlockSetEmboss(block, UI_EMBOSSN);
|
||||
|
||||
but = uiDefIconBut(block, BUT, B_CONSTRAINT_CHANGETARGET, ICON_X, *xco+262, *yco, 19, 19, list, 0.0, 0.0, 0.0, 0.0, "Delete constraint");
|
||||
uiButSetFunc(but, del_constraint_func, ob, con);
|
||||
|
||||
uiBlockSetEmboss(block, UI_EMBOSS);
|
||||
}
|
||||
|
||||
/* Set but-locks for protected settings (magic numbers are used here!) */
|
||||
if (proxy_protected)
|
||||
uiSetButLock(1, "Cannot edit Proxy-Protected Constraint");
|
||||
|
||||
but = uiDefIconBut(block, BUT, B_CONSTRAINT_CHANGETARGET, ICON_X, *xco+262, *yco, 19, 19, list, 0.0, 0.0, 0.0, 0.0, "Delete constraint");
|
||||
uiButSetFunc(but, del_constraint_func, ob, con);
|
||||
|
||||
uiBlockSetEmboss(block, UI_EMBOSS);
|
||||
|
||||
|
||||
/* Draw constraint data */
|
||||
if ((con->flag & CONSTRAINT_EXPAND) == 0) {
|
||||
(*yco) -= 21;
|
||||
@@ -1649,6 +1698,9 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
|
||||
else {
|
||||
(*yco)-=3;
|
||||
}
|
||||
|
||||
/* clear any locks set up for proxies/lib-linking */
|
||||
uiClearButLock();
|
||||
}
|
||||
|
||||
static uiBlock *add_constraintmenu(void *arg_unused)
|
||||
|
||||
@@ -247,6 +247,9 @@ void add_constraint_to_object(bConstraint *con, Object *ob)
|
||||
unique_constraint_name(con, list);
|
||||
BLI_addtail(list, con);
|
||||
|
||||
if (proxylocked_constraints_owner(ob, NULL))
|
||||
con->flag |= CONSTRAINT_PROXY_LOCAL;
|
||||
|
||||
con->flag |= CONSTRAINT_ACTIVE;
|
||||
for (con= con->prev; con; con= con->prev)
|
||||
con->flag &= ~CONSTRAINT_ACTIVE;
|
||||
@@ -258,7 +261,6 @@ void add_constraint_to_object(bConstraint *con, Object *ob)
|
||||
*/
|
||||
static void test_constraints (Object *owner, const char substring[])
|
||||
{
|
||||
|
||||
bConstraint *curcon;
|
||||
ListBase *conlist= NULL;
|
||||
int type;
|
||||
@@ -266,8 +268,6 @@ static void test_constraints (Object *owner, const char substring[])
|
||||
if (owner==NULL) return;
|
||||
|
||||
/* Check parents */
|
||||
/* Get the constraint list for this object */
|
||||
|
||||
if (strlen (substring)) {
|
||||
switch (owner->type) {
|
||||
case OB_ARMATURE:
|
||||
@@ -281,7 +281,7 @@ static void test_constraints (Object *owner, const char substring[])
|
||||
else
|
||||
type = CONSTRAINT_OBTYPE_OBJECT;
|
||||
|
||||
|
||||
/* Get the constraint list for this object */
|
||||
switch (type) {
|
||||
case CONSTRAINT_OBTYPE_OBJECT:
|
||||
conlist = &owner->constraints;
|
||||
@@ -656,12 +656,6 @@ void add_constraint(int only_IK)
|
||||
/* find active channel */
|
||||
pchanact= get_active_posechannel(ob);
|
||||
if(pchanact==NULL) return;
|
||||
|
||||
/* check protection */
|
||||
if(ob->proxy && (pchanact->bone->layer & arm->layer_protected)) {
|
||||
error("Bone is Proxy protected");
|
||||
return;
|
||||
}
|
||||
|
||||
/* find selected bone */
|
||||
for(pchansel= ob->pose->chanbase.first; pchansel; pchansel= pchansel->next) {
|
||||
@@ -745,8 +739,11 @@ void add_constraint(int only_IK)
|
||||
con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC);
|
||||
BLI_addtail(&pchanact->constraints, con);
|
||||
unique_constraint_name(con, &pchanact->constraints);
|
||||
pchanact->constflag |= PCHAN_HAS_IK; // for draw, but also for detecting while pose solving
|
||||
if(nr==11) pchanact->constflag |= PCHAN_HAS_TARGET;
|
||||
pchanact->constflag |= PCHAN_HAS_IK; /* for draw, but also for detecting while pose solving */
|
||||
if (nr==11)
|
||||
pchanact->constflag |= PCHAN_HAS_TARGET;
|
||||
if (proxylocked_constraints_owner(ob, pchanact))
|
||||
con->flag |= CONSTRAINT_PROXY_LOCAL;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -812,10 +809,14 @@ void add_constraint(int only_IK)
|
||||
BLI_addtail(&pchanact->constraints, con);
|
||||
unique_constraint_name(con, &pchanact->constraints);
|
||||
pchanact->constflag |= PCHAN_HAS_CONST; /* for draw */
|
||||
if (proxylocked_constraints_owner(ob, pchanact))
|
||||
con->flag |= CONSTRAINT_PROXY_LOCAL;
|
||||
}
|
||||
else {
|
||||
BLI_addtail(&ob->constraints, con);
|
||||
unique_constraint_name(con, &ob->constraints);
|
||||
if (proxylocked_constraints_owner(ob, NULL))
|
||||
con->flag |= CONSTRAINT_PROXY_LOCAL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -867,9 +868,9 @@ void add_constraint(int only_IK)
|
||||
else
|
||||
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); // and all its relations
|
||||
|
||||
allqueue (REDRAWVIEW3D, 0);
|
||||
allqueue (REDRAWBUTSOBJECT, 0);
|
||||
allqueue (REDRAWOOPS, 0);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
allqueue(REDRAWBUTSOBJECT, 0);
|
||||
allqueue(REDRAWOOPS, 0);
|
||||
|
||||
if (only_IK)
|
||||
BIF_undo_push("Add IK Constraint");
|
||||
|
||||
@@ -165,6 +165,9 @@ bPoseChannel *get_active_posechannel (Object *ob)
|
||||
bArmature *arm= ob->data;
|
||||
bPoseChannel *pchan;
|
||||
|
||||
if ELEM(NULL, ob, ob->pose)
|
||||
return NULL;
|
||||
|
||||
/* find active */
|
||||
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
if(pchan->bone && (pchan->bone->flag & BONE_ACTIVE) && (pchan->bone->layer & arm->layer))
|
||||
|
||||
Reference in New Issue
Block a user