Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2008-01-05 12:31:43 +0300
committerJoshua Leung <aligorith@gmail.com>2008-01-05 12:31:43 +0300
commit8e54dc2579d8e437d12dc25f34caf0f118a0a501 (patch)
treeae1bdd3d76cd5455e787f36e0aa331988c9e41da /source/blender/src/editconstraint.c
parent8ee41f8d28197f57b3c8d8ded617162159fc1ae9 (diff)
== Constraints - Code Cleanups ==
* Tidied up coding style of code in editconstraint.c - removed blank lines, made whitespace-use more consistent * Shuffled code in editconstraint.c and BIF_editconstraint.h so that it was in a more orderly fashion * Reduced code redundancy in test_constraints - tests which can apply to general constraints (target existance, and clashes with the owner) are not copied out for each constraint that needs it - ChildOf constraint now gets validated too (before it was missing such checks) * Recoded the way PyConstraints build the menu for displaying scripts available for use. It now uses dynstr instead of guessing how much memory to allocate for each entry
Diffstat (limited to 'source/blender/src/editconstraint.c')
-rw-r--r--source/blender/src/editconstraint.c832
1 files changed, 360 insertions, 472 deletions
diff --git a/source/blender/src/editconstraint.c b/source/blender/src/editconstraint.c
index 940634290bd..c569d78f90f 100644
--- a/source/blender/src/editconstraint.c
+++ b/source/blender/src/editconstraint.c
@@ -25,7 +25,7 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): none yet.
+ * Contributor(s): Joshua Leung
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
@@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
+#include "BLI_dynstr.h"
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
@@ -73,55 +74,56 @@
#include "nla.h"
#include "mydevice.h"
+/* -------------- Get Active Constraint Data ---------------------- */
ListBase *get_active_constraint_channels (Object *ob, int forcevalid)
{
char ipstr[64];
- if (!ob)
+ if (ob == NULL)
return NULL;
/* See if we are a bone constraint */
if (ob->flag & OB_POSEMODE) {
bActionChannel *achan;
bPoseChannel *pchan;
-
+
pchan = get_active_posechannel(ob);
if (pchan) {
-
/* Make sure we have an action */
- if (!ob->action){
- if (!forcevalid)
+ if (ob->action == NULL) {
+ if (forcevalid == 0)
return NULL;
- ob->action=add_empty_action("Action");
+ ob->action= add_empty_action("Action");
}
/* Make sure we have an actionchannel */
achan = get_action_channel(ob->action, pchan->name);
- if (!achan){
- if (!forcevalid)
+ if (achan == NULL) {
+ if (forcevalid == 0)
return NULL;
- achan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
-
- strcpy (achan->name, pchan->name);
- sprintf (ipstr, "%s.%s", ob->action->id.name+2, achan->name);
+ achan = MEM_callocN (sizeof(bActionChannel), "ActionChannel");
+
+ strcpy(achan->name, pchan->name);
+ sprintf(ipstr, "%s.%s", ob->action->id.name+2, achan->name);
ipstr[23]=0;
achan->ipo= add_ipo(ipstr, ID_AC);
- BLI_addtail (&ob->action->chanbase, achan);
+ BLI_addtail(&ob->action->chanbase, achan);
}
return &achan->constraintChannels;
}
- else return NULL;
+ else
+ return NULL;
}
/* else we return object constraints */
else {
- if(ob->ipoflag & OB_ACTION_OB) {
+ if (ob->ipoflag & OB_ACTION_OB) {
bActionChannel *achan = get_action_channel(ob->action, "Object");
- if(achan)
+ if (achan)
return &achan->constraintChannels;
else
return NULL;
@@ -133,14 +135,14 @@ ListBase *get_active_constraint_channels (Object *ob, int forcevalid)
/* if object in posemode, active bone constraints, else object constraints */
-ListBase *get_active_constraints(Object *ob)
+ListBase *get_active_constraints (Object *ob)
{
- if (!ob)
+ if (ob == NULL)
return NULL;
if (ob->flag & OB_POSEMODE) {
bPoseChannel *pchan;
-
+
pchan = get_active_posechannel(ob);
if (pchan)
return &pchan->constraints;
@@ -152,40 +154,46 @@ ListBase *get_active_constraints(Object *ob)
}
/* single constraint */
-bConstraint *get_active_constraint(Object *ob)
+bConstraint *get_active_constraint (Object *ob)
{
ListBase *lb= get_active_constraints(ob);
if (lb) {
bConstraint *con;
- for (con= lb->first; con; con=con->next)
+
+ for (con= lb->first; con; con=con->next) {
if (con->flag & CONSTRAINT_ACTIVE)
return con;
+ }
}
+
return NULL;
}
/* single channel, for ipo */
-bConstraintChannel *get_active_constraint_channel(Object *ob)
+bConstraintChannel *get_active_constraint_channel (Object *ob)
{
bConstraint *con;
bConstraintChannel *chan;
if (ob->flag & OB_POSEMODE) {
- if(ob->action) {
+ if (ob->action) {
bPoseChannel *pchan;
pchan = get_active_posechannel(ob);
if (pchan) {
- for (con= pchan->constraints.first; con; con= con->next)
+ for (con= pchan->constraints.first; con; con= con->next) {
if (con->flag & CONSTRAINT_ACTIVE)
break;
+ }
+
if (con) {
bActionChannel *achan = get_action_channel(ob->action, pchan->name);
if (achan) {
- for (chan= achan->constraintChannels.first; chan; chan= chan->next)
+ for (chan= achan->constraintChannels.first; chan; chan= chan->next) {
if (!strcmp(chan->name, con->name))
break;
+ }
return chan;
}
}
@@ -193,16 +201,20 @@ bConstraintChannel *get_active_constraint_channel(Object *ob)
}
}
else {
- for(con= ob->constraints.first; con; con= con->next)
- if(con->flag & CONSTRAINT_ACTIVE)
+ for (con= ob->constraints.first; con; con= con->next) {
+ if (con->flag & CONSTRAINT_ACTIVE)
break;
- if(con) {
+ }
+
+ if (con) {
ListBase *lb= get_active_constraint_channels(ob, 0);
-
- if(lb) {
- for(chan= lb->first; chan; chan= chan->next)
- if(!strcmp(chan->name, con->name))
+
+ if (lb) {
+ for (chan= lb->first; chan; chan= chan->next) {
+ if (!strcmp(chan->name, con->name))
break;
+ }
+
return chan;
}
}
@@ -211,13 +223,15 @@ bConstraintChannel *get_active_constraint_channel(Object *ob)
return NULL;
}
+/* -------------- Constraint Management (Add New, Remove, Rename) -------------------- */
-bConstraint *add_new_constraint(short type)
+/* Creates a new constraint, initialises its data, and returns it */
+bConstraint *add_new_constraint (short type)
{
bConstraint *con;
bConstraintTypeInfo *cti;
- con = MEM_callocN(sizeof(bConstraint), "constraint");
+ con = MEM_callocN(sizeof(bConstraint), "Constraint");
/* Set up a generic constraint datablock */
con->type = type;
@@ -238,7 +252,8 @@ bConstraint *add_new_constraint(short type)
return con;
}
-void add_constraint_to_object(bConstraint *con, Object *ob)
+/* Adds the given constraint to the Object-level set of constraints for the given Object */
+void add_constraint_to_object (bConstraint *con, Object *ob)
{
ListBase *list;
list = &ob->constraints;
@@ -256,361 +271,14 @@ void add_constraint_to_object(bConstraint *con, Object *ob)
}
}
-/* checks validity of object pointers, and NULLs,
- * if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag
- */
-static void test_constraints (Object *owner, const char substring[])
-{
- bConstraint *curcon;
- ListBase *conlist= NULL;
- int type;
-
- if (owner==NULL) return;
-
- /* Check parents */
- if (strlen (substring)) {
- switch (owner->type) {
- case OB_ARMATURE:
- type = CONSTRAINT_OBTYPE_BONE;
- break;
- default:
- type = CONSTRAINT_OBTYPE_OBJECT;
- break;
- }
- }
- else
- type = CONSTRAINT_OBTYPE_OBJECT;
-
- /* Get the constraint list for this object */
- switch (type) {
- case CONSTRAINT_OBTYPE_OBJECT:
- conlist = &owner->constraints;
- break;
- case CONSTRAINT_OBTYPE_BONE:
- {
- Bone *bone;
- bPoseChannel *chan;
-
- bone = get_named_bone( ((bArmature *)owner->data ), substring );
- chan = get_pose_channel(owner->pose, substring);
- if (bone && chan) {
- conlist = &chan->constraints;
- }
- }
- break;
- }
-
- /* Check all constraints - is constraint valid? */
- if (conlist) {
- for (curcon = conlist->first; curcon; curcon=curcon->next) {
- curcon->flag &= ~CONSTRAINT_DISABLE;
-
- switch (curcon->type) {
- case CONSTRAINT_TYPE_PYTHON:
- {
- bPythonConstraint *data = curcon->data;
-
- /* is there are valid script? */
- if (!data->text) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- else if (!BPY_is_pyconstraint(data->text)) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- /* does the constraint require target input... also validates targets */
- BPY_pyconstraint_update(owner, curcon);
- }
- break;
- case CONSTRAINT_TYPE_ACTION:
- {
- bActionConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if ( (data->tar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->subtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- }
- break;
- case CONSTRAINT_TYPE_LOCLIKE:
- {
- bLocateLikeConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if ( (data->tar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->subtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- }
- break;
- case CONSTRAINT_TYPE_MINMAX:
- {
- bMinMaxConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if ( (data->tar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->subtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- }
- break;
- case CONSTRAINT_TYPE_ROTLIKE:
- {
- bRotateLikeConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if ( (data->tar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->subtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- }
- break;
- case CONSTRAINT_TYPE_SIZELIKE:
- {
- bSizeLikeConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if ( (data->tar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->subtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- }
- break;
- case CONSTRAINT_TYPE_KINEMATIC:
- {
- bKinematicConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if ( (data->tar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->subtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
-
- if (data->poletar && !exist_object(data->poletar)) {
- data->poletar = NULL;
- }
- else if ( (data->poletar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->polesubtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
-
- }
- break;
- case CONSTRAINT_TYPE_TRACKTO:
- {
- bTrackToConstraint *data = curcon->data;
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if ( (data->tar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->subtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- if (data->reserved2==data->reserved1) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- if (data->reserved2+3==data->reserved1) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- }
- break;
- case CONSTRAINT_TYPE_LOCKTRACK:
- {
- bLockTrackConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if ( (data->tar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->subtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if (data->lockflag==data->trackflag) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- if (data->lockflag+3==data->trackflag) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- }
- break;
- case CONSTRAINT_TYPE_STRETCHTO:
- {
- bStretchToConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if ( (data->tar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->subtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- }
- break;
- case CONSTRAINT_TYPE_FOLLOWPATH:
- {
- bFollowPathConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- if (data->tar->type != OB_CURVE) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- if (data->upflag==data->trackflag) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- if (data->upflag+3==data->trackflag) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- }
- break;
- case CONSTRAINT_TYPE_CLAMPTO:
- {
- bClampToConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if (data->tar->type != OB_CURVE) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- else {
- Curve *cu= data->tar->data;
-
- /* auto-set 'Path' setting on curve so this works */
- cu->flag |= CU_PATH;
- }
- }
- break;
- case CONSTRAINT_TYPE_TRANSFORM:
- {
- bTransformConstraint *data = curcon->data;
-
- if (!exist_object(data->tar)) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
-
- if ( (data->tar == owner) &&
- (!get_named_bone(get_armature(owner),
- data->subtarget))) {
- curcon->flag |= CONSTRAINT_DISABLE;
- break;
- }
- }
- break;
- }
- }
- }
-}
-
-static void test_bonelist_constraints (Object *owner, ListBase *list)
-{
- Bone *bone;
-
- for (bone = list->first; bone; bone=bone->next) {
-
- test_constraints(owner, bone->name);
- test_bonelist_constraints (owner, &bone->childbase);
- }
-}
-
-void object_test_constraints (Object *owner)
-{
- test_constraints(owner, "");
-
- if(owner->type==OB_ARMATURE) {
- bArmature *arm;
- arm = get_armature(owner);
- if (arm)
- test_bonelist_constraints (owner, &arm->bonebase);
- }
-
-}
-
/* helper function for add_constriant - sets the last target for the active constraint */
-static void set_constraint_nth_target(bConstraint *con, Object *target, char subtarget[], int index)
+static void set_constraint_nth_target (bConstraint *con, Object *target, char subtarget[], int index)
{
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
int num_targets, i;
-
+
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
num_targets= BLI_countlist(&targets);
@@ -639,7 +307,7 @@ static void set_constraint_nth_target(bConstraint *con, Object *target, char sub
}
/* context: active object in posemode, active channel, optional selected channel */
-void add_constraint(int only_IK)
+void add_constraint (short only_IK)
{
Object *ob= OBACT, *obsel=NULL;
bPoseChannel *pchanact=NULL, *pchansel=NULL;
@@ -648,89 +316,94 @@ void add_constraint(int only_IK)
short nr;
/* paranoia checks */
- if(ob==NULL || ob==G.obedit) return;
+ if ((ob==NULL) || (ob==G.obedit))
+ return;
- if(ob->pose && (ob->flag & OB_POSEMODE)) {
+ if ((ob->pose) && (ob->flag & OB_POSEMODE)) {
bArmature *arm= ob->data;
/* find active channel */
pchanact= get_active_posechannel(ob);
- if(pchanact==NULL) return;
+ if (pchanact==NULL)
+ return;
/* find selected bone */
- for(pchansel= ob->pose->chanbase.first; pchansel; pchansel= pchansel->next) {
- if(pchansel!=pchanact)
- if(pchansel->bone->flag & BONE_SELECTED)
- if(pchansel->bone->layer & arm->layer)
+ for (pchansel=ob->pose->chanbase.first; pchansel; pchansel=pchansel->next) {
+ if (pchansel != pchanact) {
+ if (pchansel->bone->flag & BONE_SELECTED) {
+ if (pchansel->bone->layer & arm->layer)
break;
+ }
+ }
}
}
/* find selected object */
- for(base= FIRSTBASE; base; base= base->next)
- if( TESTBASE(base) && base->object!=ob )
+ for (base= FIRSTBASE; base; base= base->next) {
+ if ((TESTBASE(base)) && (base->object!=ob))
obsel= base->object;
+ }
/* the only_IK caller has checked for posemode! */
- if(only_IK) {
- for(con= pchanact->constraints.first; con; con= con->next) {
- if(con->type==CONSTRAINT_TYPE_KINEMATIC) break;
+ if (only_IK) {
+ for (con= pchanact->constraints.first; con; con= con->next) {
+ if (con->type==CONSTRAINT_TYPE_KINEMATIC) break;
}
- if(con) {
+ if (con) {
error("Pose Channel already has IK");
return;
}
- if(pchansel)
+ if (pchansel)
nr= pupmenu("Add IK Constraint%t|To Active Bone%x10");
- else if(obsel)
+ else if (obsel)
nr= pupmenu("Add IK Constraint%t|To Active Object%x10");
else
nr= pupmenu("Add IK Constraint%t|To New Empty Object%x10|Without Target%x11");
}
else {
- if(pchanact) {
- if(pchansel)
+ if (pchanact) {
+ if (pchansel)
nr= pupmenu("Add Constraint to Active Bone%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18");
- else if(obsel && obsel->type==OB_CURVE)
+ else if ((obsel) && (obsel->type==OB_CURVE))
nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|%l|Action%x16|Script%x18");
- else if(obsel)
+ else if (obsel)
nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18");
else
nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18");
}
else {
- if(obsel && obsel->type==OB_CURVE)
+ if ((obsel) && (obsel->type==OB_CURVE))
nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|%l|Action%x16|Script%x18");
- else if(obsel)
+ else if (obsel)
nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18");
else
nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18");
}
}
- if(nr<1) return;
+ if (nr < 1) return;
/* handle IK separate */
- if(nr==10 || nr==11) {
-
- /* prevent weird chains... */
- if(pchansel) {
+ if (nr==10 || nr==11) {
+ /* ik - prevent weird chains... */
+ if (pchansel) {
bPoseChannel *pchan= pchanact;
- while(pchan) {
- if(pchan==pchansel) break;
+ while (pchan) {
+ if (pchan==pchansel) break;
pchan= pchan->parent;
}
- if(pchan) {
+ if (pchan) {
error("IK root cannot be linked to IK tip");
return;
}
+
pchan= pchansel;
- while(pchan) {
- if(pchan==pchanact) break;
+ while (pchan) {
+ if (pchan==pchanact) break;
pchan= pchan->parent;
}
- if(pchan) {
+ if (pchan) {
error("IK tip cannot be linked to IK root");
return;
}
@@ -746,7 +419,7 @@ void add_constraint(int only_IK)
con->flag |= CONSTRAINT_PROXY_LOCAL;
}
else {
-
+ /* normal constraints - add data */
if (nr==1) con = add_new_constraint(CONSTRAINT_TYPE_LOCLIKE);
else if (nr==2) con = add_new_constraint(CONSTRAINT_TYPE_ROTLIKE);
else if (nr==3) con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
@@ -824,7 +497,7 @@ void add_constraint(int only_IK)
if (pchansel) {
set_constraint_nth_target(con, ob, pchansel->name, 0);
}
- else if(obsel) {
+ else if (obsel) {
set_constraint_nth_target(con, obsel, "", 0);
}
else if (ELEM4(nr, 11, 13, 14, 15)==0) { /* add new empty as target */
@@ -839,7 +512,7 @@ void add_constraint(int only_IK)
/* transform cent to global coords for loc */
if (pchanact) {
- if(only_IK)
+ if (only_IK)
VecMat4MulVecfl(obt->loc, ob->obmat, pchanact->pose_tail);
else
VecMat4MulVecfl(obt->loc, ob->obmat, pchanact->pose_head);
@@ -856,7 +529,7 @@ void add_constraint(int only_IK)
/* active flag */
con->flag |= CONSTRAINT_ACTIVE;
- for(con= con->prev; con; con= con->prev)
+ for (con= con->prev; con; con= con->prev)
con->flag &= ~CONSTRAINT_ACTIVE;
DAG_scene_sort(G.scene); // sort order of objects
@@ -879,30 +552,36 @@ void add_constraint(int only_IK)
}
-void ob_clear_constraints(void)
+/* Remove all constraints from the active object */
+void ob_clear_constraints (void)
{
Object *ob= OBACT;
/* paranoia checks */
- if(!ob) return;
- if(ob==G.obedit || (ob->flag & OB_POSEMODE)) return;
+ if ((ob==NULL) || (ob==G.obedit) || (ob->flag & OB_POSEMODE))
+ return;
- if(okee("Clear Constraints")==0) return;
+ /* get user permission */
+ if (okee("Clear Constraints")==0)
+ return;
+ /* do freeing */
free_constraints(&ob->constraints);
+ /* do updates */
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
- allqueue (REDRAWVIEW3D, 0);
- allqueue (REDRAWBUTSOBJECT, 0);
- allqueue (REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWOOPS, 0);
BIF_undo_push("Clear Constraint(s)");
-
}
-/* con already has the new name */
-void rename_constraint(Object *ob, bConstraint *con, char *oldname)
+/* Rename the given constraint
+ * - con already has the new name
+ */
+void rename_constraint (Object *ob, bConstraint *con, char *oldname)
{
bConstraint *tcon;
bConstraintChannel *conchan;
@@ -911,33 +590,35 @@ void rename_constraint(Object *ob, bConstraint *con, char *oldname)
char *channame="";
/* get context by searching for con (primitive...) */
- for(tcon= ob->constraints.first; tcon; tcon= tcon->next)
- if(tcon==con)
+ for (tcon= ob->constraints.first; tcon; tcon= tcon->next) {
+ if (tcon==con)
break;
+ }
- if(tcon) {
+ if (tcon) {
conlist= &ob->constraints;
channame= "Object";
from_object= 1;
}
- else if(ob->pose) {
+ else if (ob->pose) {
bPoseChannel *pchan;
- for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- for(tcon= pchan->constraints.first; tcon; tcon= tcon->next) {
- if(tcon==con)
+ for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ for (tcon= pchan->constraints.first; tcon; tcon= tcon->next) {
+ if (tcon==con)
break;
}
- if(tcon)
+ if (tcon)
break;
}
- if(tcon) {
+
+ if (tcon) {
conlist= &pchan->constraints;
channame= pchan->name;
}
}
- if(conlist==NULL) {
+ if (conlist==NULL) {
printf("rename constraint failed\n"); /* should not happen in UI */
return;
}
@@ -946,29 +627,232 @@ void rename_constraint(Object *ob, bConstraint *con, char *oldname)
unique_constraint_name (con, conlist);
/* own channels */
- if(from_object) {
- for(conchan= ob->constraintChannels.first; conchan; conchan= conchan->next) {
- if( strcmp(oldname, conchan->name)==0 )
+ if (from_object) {
+ for (conchan= ob->constraintChannels.first; conchan; conchan= conchan->next) {
+ if ( strcmp(oldname, conchan->name)==0 )
BLI_strncpy(conchan->name, con->name, sizeof(conchan->name));
}
}
+
/* own action */
- if(ob->action) {
+ if (ob->action) {
bActionChannel *achan= get_action_channel(ob->action, channame);
- if(achan) {
+ if (achan) {
conchan= get_constraint_channel(&achan->constraintChannels, oldname);
- if(conchan)
+ if (conchan)
BLI_strncpy(conchan->name, con->name, sizeof(conchan->name));
}
}
+}
+
+
+/* ------------- Constraint Sanity Testing ------------------- */
+
+/* checks validity of object pointers, and NULLs,
+ * if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag
+ */
+static void test_constraints (Object *owner, const char substring[])
+{
+ bConstraint *curcon;
+ ListBase *conlist= NULL;
+ int type;
+ if (owner==NULL) return;
+
+ /* Check parents */
+ if (strlen (substring)) {
+ switch (owner->type) {
+ case OB_ARMATURE:
+ type = CONSTRAINT_OBTYPE_BONE;
+ break;
+ default:
+ type = CONSTRAINT_OBTYPE_OBJECT;
+ break;
+ }
+ }
+ else
+ type = CONSTRAINT_OBTYPE_OBJECT;
+
+ /* Get the constraint list for this object */
+ switch (type) {
+ case CONSTRAINT_OBTYPE_OBJECT:
+ conlist = &owner->constraints;
+ break;
+ case CONSTRAINT_OBTYPE_BONE:
+ {
+ Bone *bone;
+ bPoseChannel *chan;
+
+ bone = get_named_bone( ((bArmature *)owner->data ), substring );
+ chan = get_pose_channel(owner->pose, substring);
+ if (bone && chan) {
+ conlist = &chan->constraints;
+ }
+ }
+ break;
+ }
+
+ /* Check all constraints - is constraint valid? */
+ if (conlist) {
+ for (curcon = conlist->first; curcon; curcon=curcon->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(curcon);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* clear disabled-flag first */
+ curcon->flag &= ~CONSTRAINT_DISABLE;
+
+ /* Check specialised data (settings) for constraints that need this */
+ if (curcon->type == CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = curcon->data;
+
+ /* is there are valid script? */
+ if (data->text == NULL) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (BPY_is_pyconstraint(data->text)==0) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else {
+ /* does the constraint require target input... also validates targets */
+ BPY_pyconstraint_update(owner, curcon);
+ }
+
+ /* targets have already been checked for this */
+ continue;
+ }
+ else if (curcon->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = curcon->data;
+
+ /* bad: we need a separate set of checks here as poletarget is
+ * optional... otherwise poletarget must exist too or else
+ * the constraint is deemed invalid
+ */
+ if (exist_object(data->tar) == 0) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->tar == owner) {
+ if (!get_named_bone(get_armature(owner), data->subtarget)) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ if (data->poletar) {
+ if (exist_object(data->poletar) == 0) {
+ data->poletar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->poletar == owner) {
+ if (!get_named_bone(get_armature(owner), data->polesubtarget)) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ }
+ }
+ else if (curcon->type == CONSTRAINT_TYPE_ACTION) {
+ bActionConstraint *data = curcon->data;
+
+ /* validate action */
+ if (data->act == NULL)
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (curcon->type == CONSTRAINT_TYPE_FOLLOWPATH) {
+ bFollowPathConstraint *data = curcon->data;
+
+ /* don't allow track/up axes to be the same */
+ if (data->upflag==data->trackflag)
+ curcon->flag |= CONSTRAINT_DISABLE;
+ if (data->upflag+3==data->trackflag)
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (curcon->type == CONSTRAINT_TYPE_TRACKTO) {
+ bTrackToConstraint *data = curcon->data;
+
+ /* don't allow track/up axes to be the same */
+ if (data->reserved2==data->reserved1)
+ curcon->flag |= CONSTRAINT_DISABLE;
+ if (data->reserved2+3==data->reserved1)
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (curcon->type == CONSTRAINT_TYPE_LOCKTRACK) {
+ bLockTrackConstraint *data = curcon->data;
+
+ if (data->lockflag==data->trackflag)
+ curcon->flag |= CONSTRAINT_DISABLE;
+ if (data->lockflag+3==data->trackflag)
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+
+ /* Check targets for constraints */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(curcon, &targets);
+
+ /* disable and clear constraints targets that are incorrect */
+ for (ct= targets.first; ct; ct= ct->next) {
+ /* general validity checks (for those constraints that need this) */
+ if (exist_object(ct->tar) == 0) {
+ ct->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (ct->tar == owner) {
+ if (!get_named_bone(get_armature(owner), ct->subtarget)) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ /* target checks for specific constraints */
+ if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) {
+ if (ct->tar) {
+ if (ct->tar->type != OB_CURVE) {
+ ct->tar= NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else {
+ Curve *cu= ct->tar->data;
+
+ /* auto-set 'Path' setting on curve so this works */
+ cu->flag |= CU_PATH;
+ }
+ }
+ }
+ }
+
+ /* free any temporary targets */
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(curcon, &targets, 0);
+ }
+ }
+ }
+}
+
+static void test_bonelist_constraints (Object *owner, ListBase *list)
+{
+ Bone *bone;
+
+ for (bone = list->first; bone; bone=bone->next) {
+ test_constraints(owner, bone->name);
+ test_bonelist_constraints (owner, &bone->childbase);
+ }
+}
+
+void object_test_constraints (Object *owner)
+{
+ test_constraints(owner, "");
+
+ if (owner->type==OB_ARMATURE) {
+ bArmature *arm= get_armature(owner);
+
+ if (arm)
+ test_bonelist_constraints (owner, &arm->bonebase);
+ }
}
/* ********************** CONSTRAINT-SPECIFIC STUFF ********************* */
/* ------------- PyConstraints ------------------ */
/* this callback sets the text-file to be used for selected menu item */
-void validate_pyconstraint_cb(void *arg1, void *arg2)
+void validate_pyconstraint_cb (void *arg1, void *arg2)
{
bPythonConstraint *data = arg1;
Text *text;
@@ -981,42 +865,44 @@ void validate_pyconstraint_cb(void *arg1, void *arg2)
}
/* this returns a string for the list of usable pyconstraint script names */
-char *buildmenu_pyconstraints(Text *con_text, int *pyconindex)
+char *buildmenu_pyconstraints (Text *con_text, int *pyconindex)
{
+ DynStr *pupds= BLI_dynstr_new();
Text *text;
- char *menustr = MEM_callocN(128, "menustr pyconstraints");
- char *name, stmp[128];
- int buf = 128;
- int used = strlen("Scripts: %t") + 1;
+ char *str;
+ char buf[64];
int i;
-
- sprintf(menustr, "%s", "Scripts: %t");
+ /* add title first */
+ sprintf(buf, "Scripts: %%t|");
+ BLI_dynstr_append(pupds, buf);
+
+ /* loop through markers, adding them */
for (text=G.main->text.first, i=1; text; i++, text=text->id.next) {
/* this is important to ensure that right script is shown as active */
if (text == con_text) *pyconindex = i;
- /* menu entry is length of name + 3(len(|%X)) + 6 characters for the int.*/
+ /* only include valid pyconstraint scripts */
if (BPY_is_pyconstraint(text)) {
- name= text->id.name;
- if (strlen(name)+used+10 >= buf) {
- char *newbuf = MEM_callocN(buf+128, "menustr pyconstraints 2");
- memcpy(newbuf, menustr, used);
- MEM_freeN(menustr);
- menustr = newbuf;
- buf += 128;
- }
- sprintf(stmp, "|%s%%x%d", name, i);
- strcat(menustr, stmp);
- used += strlen(name)+10;
+ BLI_dynstr_append(pupds, text->id.name+2);
+
+ sprintf(buf, "%%x%d", i);
+ BLI_dynstr_append(pupds, buf);
+
+ if (text->id.next)
+ BLI_dynstr_append(pupds, "|");
}
}
- return menustr;
+ /* convert to normal MEM_malloc'd string */
+ str= BLI_dynstr_get_cstring(pupds);
+ BLI_dynstr_free(pupds);
+
+ return str;
}
/* this callback gets called when the 'refresh' button of a pyconstraint gets pressed */
-void update_pyconstraint_cb(void *arg1, void *arg2)
+void update_pyconstraint_cb (void *arg1, void *arg2)
{
Object *owner= (Object *)arg1;
bConstraint *con= (bConstraint *)arg2;
@@ -1030,7 +916,8 @@ void update_pyconstraint_cb(void *arg1, void *arg2)
/* ChildOf Constraint - set inverse callback */
void childof_const_setinv (void *conv, void *unused)
{
- bChildOfConstraint *data= (bChildOfConstraint *)conv;
+ bConstraint *con= (bConstraint *)conv;
+ bChildOfConstraint *data= (bChildOfConstraint *)con->data;
Object *ob= OBACT;
bPoseChannel *pchan= NULL;
@@ -1097,7 +984,8 @@ void childof_const_setinv (void *conv, void *unused)
/* ChildOf Constraint - clear inverse callback */
void childof_const_clearinv (void *conv, void *unused)
{
- bChildOfConstraint *data= (bChildOfConstraint *)conv;
+ bConstraint *con= (bConstraint *)conv;
+ bChildOfConstraint *data= (bChildOfConstraint *)con->data;
/* simply clear the matrix */
Mat4One(data->invmat);