== Constraints System - Recode 2 ==

Once again, I've recoded the constraints system. This time, the goals were:
* To make it more future-proof by 'modernising' the coding style. The long functions filled with switch statements, have given way to function-pointers with smaller functions for specific purposes.
* To make it support constraints which use multiple targets more readily that it did. In the past, it was assumed that constraints could only have at most one target.

As a result, a lot of code has been shuffled around, and modified. Also, the subversion number has been bumped up.

Known issues:
* PyConstraints, which were the main motivation for supporting multiple-targets, are currently broken. There are some bimport() error that keeps causing problems. I've also temporarily removed the doDriver support, although it may return in another form soon. 
* Constraints BPy-API is currently has a few features which currently don't work yet
* Outliner currently only displays the names of the constraints instead of the fancy subtarget/target/constraint-name display it used to do. What gets displayed here needs further investigation, as the old way was certainly not that great (and is not compatible with the new system too)
This commit is contained in:
Joshua Leung 2007-10-21 23:00:29 +00:00
parent a4e8e87983
commit 6422a740c2
25 changed files with 4114 additions and 3303 deletions

@ -21,17 +21,21 @@ from Blender import Draw
from Blender import Mathutils
import math
USE_TARGET = True
'''
This variable specifies the number of targets
that this constraint can use
'''
NUM_TARGETS = 1
'''
This function is called to evaluate the constraint
obmatrix: (Matrix) copy of owner's worldspace matrix
targetmatrix: (Matrix) copy of target's worldspace matrix (where applicable)
obmatrix: (Matrix) copy of owner's 'ownerspace' matrix
targetmatrices: (List) list of copies of the 'targetspace' matrices of the targets (where applicable)
idprop: (IDProperties) wrapped data referring to this
constraint instance's idproperties
'''
def doConstraint(obmatrix, targetmatrix, idprop):
def doConstraint(obmatrix, targetmatrices, idprop):
# Separate out the tranformation components for easy access.
obloc = obmatrix.translationPart() # Translation
obrot = obmatrix.toEuler() # Rotation
@ -60,9 +64,9 @@ def doConstraint(obmatrix, targetmatrix, idprop):
'''
This function manipulates the target matrix prior to sending it to doConstraint()
This function manipulates the matrix of a target prior to sending it to doConstraint()
target_object: wrapped data, representing the target object
subtarget_bone: wrapped data, representing the subtarget pose-bone (where applicable)
subtarget_bone: wrapped data, representing the subtarget pose-bone/vertex-group (where applicable)
target_matrix: (Matrix) the transformation matrix of the target
id_properties_of_constraint: (IDProperties) wrapped idproperties
'''
@ -72,8 +76,8 @@ def doTarget(target_object, subtarget_bone, target_matrix, id_properties_of_cons
'''
This function draws a pupblock that lets the user set
the values of custom settings the constraint defines.
This function is called when the user presses the settings button.
the values of custom settings the constraint defines.
This function is called when the user presses the settings button.
idprop: (IDProperties) wrapped data referring to this
constraint instance's idproperties
'''

@ -65,6 +65,7 @@ struct IpoDriver; /* DNA_curve_types.h */
struct Object;
struct bPythonConstraint;
struct bConstraintOb;
struct bConstraintTarget;
void BPY_do_pyscript (struct ID *id, short int event);
void BPY_clear_script (struct Script *script);
void BPY_free_compiled_text (struct Text *text);
@ -74,9 +75,9 @@ float BPY_pydriver_eval(struct IpoDriver *driver);
void BPY_pydriver_update(void);
/* button python evaluation */
int BPY_button_eval(char *expr, double *value);
void BPY_pyconstraint_eval(struct bPythonConstraint *con, float ownermat[][4], float targetmat[][4]);
void BPY_pyconstraint_driver(struct bPythonConstraint *con, struct bConstraintOb *cob, struct Object *target, char subtarget[]);
int BPY_pyconstraint_targets(struct bPythonConstraint *con, float targetmat[][4]);
/* pyconstraints */
void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
void BPY_pyconstraint_targets(struct bPythonConstraint *con, struct bConstraintTarget *ct);
/* writefile.c */

@ -44,7 +44,7 @@ struct ListBase;
struct MemFile;
#define BLENDER_VERSION 245
#define BLENDER_SUBVERSION 6
#define BLENDER_SUBVERSION 7
#define BLENDER_MINVERSION 240
#define BLENDER_MINSUBVERSION 0

@ -33,22 +33,12 @@
#ifndef BKE_CONSTRAINT_H
#define BKE_CONSTRAINT_H
struct bConstraint;
struct bConstraintTarget;
struct ListBase;
struct Object;
struct bConstraintChannel;
struct bPoseChannel;
struct bAction;
struct bArmature;
/* ---------------------------------------------------------------------------- */
/* Constraint target/owner types */
#define TARGET_OBJECT 1 /* string is "" */
#define TARGET_BONE 2 /* string is bone-name */
#define TARGET_VERT 3 /* string is vertex-group name */
#define TARGET_CV 4 /* string is vertex-group name - is not available until curves get vgroups */
/* ---------------------------------------------------------------------------- */
@ -63,28 +53,79 @@ typedef struct bConstraintOb {
short type; /* type of owner */
} bConstraintOb;
/* ---------------------------------------------------------------------------- */
/* Constraint Type-Info (shorthand in code = cti):
* This struct provides function pointers for runtime, so that functions can be
* written more generally (with fewer/no special exceptions for various constraints).
*
* Callers of these functions must check that they actually point to something useful,
* as some constraints don't define some of these.
*
* Warning: it is not too advisable to reorder order of members of this struct,
* as you'll have to edit quite a few ($NUM_CONSTRAINT_TYPES) of these
* structs.
*/
typedef struct bConstraintTypeInfo {
/* admin/ident */
short type; /* CONSTRAINT_TYPE_### */
short size; /* size in bytes of the struct */
char name[32]; /* name constraint in interface */
char structName[32]; /* name of struct for SDNA */
/* data management function pointers - special handling */
/* free any data that is allocated separately (optional) */
void (*free_data)(struct bConstraint *con);
/* adjust pointer to other ID-data using ID_NEW(), but not to targets (optional) */
void (*relink_data)(struct bConstraint *con);
/* copy any special data that is allocated separately (optional) */
void (*copy_data)(struct bConstraint *con, struct bConstraint *src);
/* set settings for data that will be used for bConstraint.data (memory already allocated) */
void (*new_data)(void *cdata);
/* target handling function pointers */
/* for multi-target constraints: return that list; otherwise make a temporary list */
void (*get_constraint_targets)(struct bConstraint *con, struct ListBase *list);
/* for single-target constraints only: flush data back to source data, and the free memory used */
void (*flush_constraint_targets)(struct bConstraint *con, struct ListBase *list, short nocopy);
/* evaluation */
/* set the ct->matrix for the given constraint target (at the given ctime) */
void (*get_target_matrix)(struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime);
/* evaluate the constraint for the given time */
void (*evaluate_constraint)(struct bConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
} bConstraintTypeInfo;
/* Function Prototypes for bConstraintTypeInfo's */
bConstraintTypeInfo *constraint_get_typeinfo(struct bConstraint *con);
bConstraintTypeInfo *get_constraint_typeinfo(int type);
/* ---------------------------------------------------------------------------- */
/* Useful macros for testing various common flag combinations */
/* Constraint Target Macros */
#define VALID_CONS_TARGET(ct) ((ct) && (ct->tar))
/* ---------------------------------------------------------------------------- */
/* Constraint function prototypes */
void unique_constraint_name(struct bConstraint *con, struct ListBase *list);
void *new_constraint_data(short type);
void free_constraints(struct ListBase *conlist);
void copy_constraints(struct ListBase *dst, struct ListBase *src);
void relink_constraints(struct ListBase *list);
void free_constraint_data(struct bConstraint *con);
/* Constraint Channel function prototypes */
struct bConstraintChannel *get_constraint_channel(ListBase *list, const char *name);
struct bConstraintChannel *verify_constraint_channel(ListBase *list, const char *name);
void do_constraint_channels(struct ListBase *conbase, struct ListBase *chanbase, float ctime, int onlydrivers);
void copy_constraint_channels(ListBase *dst, ListBase *src);
void clone_constraint_channels(struct ListBase *dst, struct ListBase *src);
void free_constraint_channels(ListBase *chanbase);
/* Target function prototypes */
char constraint_has_target(struct bConstraint *con);
struct Object *get_constraint_target(struct bConstraint *con, char **subtarget);
void set_constraint_target(struct bConstraint *con, struct Object *ob, char *subtarget);
/* Constraint Channel function prototypes */
struct bConstraintChannel *get_constraint_channel(struct ListBase *list, const char *name);
struct bConstraintChannel *verify_constraint_channel(struct ListBase *list, const char *name);
void do_constraint_channels(struct ListBase *conbase, struct ListBase *chanbase, float ctime, short onlydrivers);
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);
@ -92,8 +133,8 @@ void constraints_clear_evalob(struct bConstraintOb *cob);
void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[][4], short from, short to);
short get_constraint_target_matrix(struct bConstraint *con, short ownertype, void *ownerdata, float mat[][4], float time);
void solve_constraints (struct ListBase *conlist, struct bConstraintOb *cob, float ctime);
void get_constraint_target_matrix(struct bConstraint *con, short ownertype, void *ownerdata, float mat[][4], float ctime);
void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime);
#endif

@ -57,6 +57,8 @@ struct RenderResult;
struct Object;
struct bPythonConstraint;
struct bConstraintOb;
struct bConstraintTarget;
struct ListBase;
char *getIpoCurveName( struct IpoCurve * icu );
void insert_vert_icu(struct IpoCurve *icu, float x, float y, short fast);
@ -128,16 +130,12 @@ int BPY_button_eval(char *expr, double *value)
}
/* PyConstraints - BPY_interface.c */
void BPY_pyconstraint_eval(struct bPythonConstraint *con, float ownermat[][4], float targetmat[][4])
void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets)
{
}
void BPY_pyconstraint_driver(struct bPythonConstraint *con, struct bConstraintOb *cob, struct Object *target, char subtarget[])
void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct)
{
}
int BPY_pyconstraint_targets(struct bPythonConstraint *con, float targetmat[][4])
{
return 0;
}
/* writefile.c */

@ -1239,7 +1239,6 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
bPose *pose= ob->pose, *frompose= from->pose;
bPoseChannel *pchan, *pchanp, pchanw;
bConstraint *con;
char *str;
if(frompose==NULL) return;
@ -1267,8 +1266,23 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
copy_constraints(&pchanw.constraints, &pchanp->constraints);
for(con= pchanw.constraints.first; con; con= con->next) {
if(from==get_constraint_target(con, &str))
set_constraint_target(con, ob, NULL);
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
for (ct= targets.first; ct; ct= ct->next) {
if (ct->tar == from) {
ct->tar = ob;
strcpy(ct->subtarget, "");
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 0);
}
}
/* free stuff from current channel */
@ -1609,45 +1623,47 @@ static void execute_posetree(Object *ob, PoseTree *tree)
Mat4MulMat4 (imat, rootmat, ob->obmat);
Mat4Invert (goalinv, imat);
for(target=tree->targets.first; target; target=target->next) {
for (target=tree->targets.first; target; target=target->next) {
data= (bKinematicConstraint*)target->con->data;
/* 1.0=ctime, we pass on object for auto-ik */
get_constraint_target_matrix(target->con, TARGET_BONE, ob, rootmat, 1.0);
/* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
* strictly speaking, it is a posechannel)
*/
get_constraint_target_matrix(target->con, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
/* and set and transform goal */
Mat4MulMat4(goal, rootmat, goalinv);
VECCOPY(goalpos, goal[3]);
Mat3CpyMat4(goalrot, goal);
/* do we need blending? */
if(target->con->enforce!=1.0) {
if (target->con->enforce!=1.0) {
float q1[4], q2[4], q[4];
float fac= target->con->enforce;
float mfac= 1.0-fac;
pchan= tree->pchan[target->tip];
/* end effector in world space */
Mat4CpyMat4(end_pose, pchan->pose_mat);
VECCOPY(end_pose[3], pchan->pose_tail);
Mat4MulSerie(world_pose, goalinv, ob->obmat, end_pose, 0, 0, 0, 0, 0);
/* blend position */
goalpos[0]= fac*goalpos[0] + mfac*world_pose[3][0];
goalpos[1]= fac*goalpos[1] + mfac*world_pose[3][1];
goalpos[2]= fac*goalpos[2] + mfac*world_pose[3][2];
/* blend rotation */
Mat3ToQuat(goalrot, q1);
Mat4ToQuat(world_pose, q2);
QuatInterpol(q, q1, q2, mfac);
QuatToMat3(q, goalrot);
}
iktarget= iktree[target->tip];
if(data->weight != 0.0)
IK_SolverAddGoal(solver, iktarget, goalpos, data->weight);
if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0) && (data->flag & CONSTRAINT_IK_AUTO)==0)
@ -1932,7 +1948,7 @@ static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime)
/* prepare PoseChannel for Constraint solving
* - makes a copy of matrix, and creates temporary struct to use
*/
cob= constraints_make_evalob(ob, pchan, TARGET_BONE);
cob= constraints_make_evalob(ob, pchan, CONSTRAINT_OBTYPE_BONE);
/* Solve PoseChannel's Constraints */
solve_constraints(&pchan->constraints, cob, ctime); // ctime doesnt alter objects

File diff suppressed because it is too large Load Diff

@ -368,27 +368,34 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int
if (ob->pose){
bPoseChannel *pchan;
bConstraint *con;
Object * target;
char *subtarget;
for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next){
for (con = pchan->constraints.first; con; con=con->next){
if (constraint_has_target(con)) {
for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
for (con = pchan->constraints.first; con; con=con->next) {
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
target = get_constraint_target(con, &subtarget);
if (target!=ob) {
// fprintf(stderr,"armature %s target :%s \n", ob->id.name, target->id.name);
node3 = dag_get_node(dag, target);
if(subtarget && subtarget[0])
dag_add_relation(dag,node3,node, DAG_RL_OB_DATA|DAG_RL_DATA_DATA);
else if(ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO))
dag_add_relation(dag,node3,node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
else
dag_add_relation(dag,node3,node, DAG_RL_OB_DATA);
for (ct= targets.first; ct; ct= ct->next) {
if (ct->tar != ob) {
// fprintf(stderr,"armature %s target :%s \n", ob->id.name, target->id.name);
node3 = dag_get_node(dag, ct->tar);
if (ct->subtarget[0])
dag_add_relation(dag,node3,node, DAG_RL_OB_DATA|DAG_RL_DATA_DATA);
else if(ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO))
dag_add_relation(dag,node3,node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
else
dag_add_relation(dag,node3,node, DAG_RL_OB_DATA);
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 1);
}
}
}
}
@ -581,20 +588,35 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int
}
for (con = ob->constraints.first; con; con=con->next) {
if (constraint_has_target(con)) {
char *str;
Object *obt= get_constraint_target(con, &str);
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
node2 = dag_get_node(dag, obt);
if(ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO))
dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB);
else {
if(ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && str && str[0])
dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB);
for (ct= targets.first; ct; ct= ct->next) {
Object *obt;
if (ct->tar)
obt= ct->tar;
else
dag_add_relation(dag, node2, node, DAG_RL_OB_OB);
continue;
node2 = dag_get_node(dag, obt);
if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO))
dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB);
else {
if (ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0]))
dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB);
else
dag_add_relation(dag, node2, node, DAG_RL_OB_OB);
}
addtoroot = 0;
}
addtoroot = 0;
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 1);
}
}
@ -1718,10 +1740,23 @@ static void dag_object_time_update_flags(Object *ob)
if(ob->ipo) ob->recalc |= OB_RECALC_OB;
else if(ob->constraints.first) {
bConstraint *con;
for (con = ob->constraints.first; con; con=con->next){
if (constraint_has_target(con)) {
ob->recalc |= OB_RECALC_OB;
break;
for (con = ob->constraints.first; con; con=con->next) {
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
for (ct= targets.first; ct; ct= ct->next) {
if (ct->tar) {
ob->recalc |= OB_RECALC_OB;
break;
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 1);
}
}
}
@ -2076,42 +2111,50 @@ void DAG_pose_sort(Object *ob)
dag_add_parent_relation(dag, node2, node, 0);
addtoroot = 0;
}
for (con = pchan->constraints.first; con; con=con->next){
if (constraint_has_target(con)) {
char *subtarget;
Object *target = get_constraint_target(con, &subtarget);
for (con = pchan->constraints.first; con; con=con->next) {
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
if (target==ob && subtarget) {
bPoseChannel *target= get_pose_channel(ob->pose, subtarget);
if(target) {
node2= dag_get_node(dag, target);
dag_add_relation(dag, node2, node, 0);
dag_add_parent_relation(dag, node2, node, 0);
if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
bKinematicConstraint *data = (bKinematicConstraint*)con->data;
bPoseChannel *parchan;
int segcount= 0;
for (ct= targets.first; ct; ct= ct->next) {
if (ct->tar==ob && ct->subtarget[0]) {
bPoseChannel *target= get_pose_channel(ob->pose, ct->subtarget);
if (target) {
node2= dag_get_node(dag, target);
dag_add_relation(dag, node2, node, 0);
dag_add_parent_relation(dag, node2, node, 0);
/* exclude tip from chain? */
if(!(data->flag & CONSTRAINT_IK_TIP))
parchan= pchan->parent;
else
parchan= pchan;
/* Walk to the chain's root */
while (parchan){
node3= dag_get_node(dag, parchan);
dag_add_relation(dag, node2, node3, 0);
dag_add_parent_relation(dag, node2, node3, 0);
if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
bPoseChannel *parchan;
int segcount= 0;
segcount++;
if(segcount==data->rootbone || segcount>255) break; // 255 is weak
parchan= parchan->parent;
/* exclude tip from chain? */
if(!(data->flag & CONSTRAINT_IK_TIP))
parchan= pchan->parent;
else
parchan= pchan;
/* Walk to the chain's root */
while (parchan) {
node3= dag_get_node(dag, parchan);
dag_add_relation(dag, node2, node3, 0);
dag_add_parent_relation(dag, node2, node3, 0);
segcount++;
if (segcount==data->rootbone || segcount>255) break; // 255 is weak
parchan= parchan->parent;
}
}
}
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 1);
}
}
if (addtoroot == 1 ) {

@ -264,7 +264,6 @@ void unlink_object(Object *ob)
bConstraint *con;
bActionStrip *strip;
int a;
char *str;
unlink_controllers(&ob->controllers);
unlink_actuators(&ob->actuators);
@ -313,9 +312,23 @@ void unlink_object(Object *ob)
bPoseChannel *pchan;
for(pchan= obt->pose->chanbase.first; pchan; pchan= pchan->next) {
for (con = pchan->constraints.first; con; con=con->next) {
if(ob==get_constraint_target(con, &str)) {
set_constraint_target(con, NULL, NULL);
obt->recalc |= OB_RECALC_DATA;
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
for (ct= targets.first; ct; ct= ct->next) {
if (ct->tar == ob) {
ct->tar = NULL;
strcpy(ct->subtarget, "");
obt->recalc |= OB_RECALC_DATA;
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 0);
}
}
if(pchan->custom==ob)
@ -326,9 +339,23 @@ void unlink_object(Object *ob)
sca_remove_ob_poin(obt, ob);
for (con = obt->constraints.first; con; con=con->next) {
if(ob==get_constraint_target(con, &str)) {
set_constraint_target(con, NULL, NULL);
obt->recalc |= OB_RECALC_OB;
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
for (ct= targets.first; ct; ct= ct->next) {
if (ct->tar == ob) {
ct->tar = NULL;
strcpy(ct->subtarget, "");
obt->recalc |= OB_RECALC_DATA;
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 0);
}
}
@ -925,11 +952,27 @@ static void copy_object_pose(Object *obn, Object *ob)
for (chan = obn->pose->chanbase.first; chan; chan=chan->next){
bConstraint *con;
char *str;
chan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
for(con= chan->constraints.first; con; con= con->next) {
if(ob==get_constraint_target(con, &str))
set_constraint_target(con, obn, NULL);
for (con= chan->constraints.first; con; con= con->next) {
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
for (ct= targets.first; ct; ct= ct->next) {
if (ct->tar == ob) {
ct->tar = obn;
strcpy(ct->subtarget, "");
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 0);
}
}
}
}
@ -1606,7 +1649,7 @@ void where_is_object_time(Object *ob, float ctime)
if (ob->constraints.first) {
bConstraintOb *cob;
cob= constraints_make_evalob(ob, NULL, TARGET_OBJECT);
cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
/* constraints need ctime, not stime. Some call where_is_object_time and bsystem_time */
solve_constraints (&ob->constraints, cob, ctime);
@ -1783,7 +1826,7 @@ for a lamp that is the child of another object */
if (ob->constraints.first) {
bConstraintOb *cob;
cob= constraints_make_evalob(ob, NULL, TARGET_OBJECT);
cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
solve_constraints (&ob->constraints, cob, G.scene->r.cfra);
constraints_clear_evalob(cob);
}

@ -1620,9 +1620,12 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
switch (con->type) {
case CONSTRAINT_TYPE_PYTHON:
{
bPythonConstraint *data;
data= (bPythonConstraint*)con->data;
data->tar = newlibadr(fd, id->lib, data->tar);
bPythonConstraint *data= (bPythonConstraint*)con->data;
bConstraintTarget *ct;
for (ct= data->targets.first; ct; ct= ct->next)
ct->tar = newlibadr(fd, id->lib, ct->tar);
data->text = newlibadr(fd, id->lib, data->text);
//IDP_LibLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
@ -5257,7 +5260,9 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
if (ob->track){
bConstraint *con;
bConstraintTypeInfo *cti;
bTrackToConstraint *data;
void *cdata;
list = &ob->constraints;
if (list)
@ -5268,9 +5273,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
con->flag |= CONSTRAINT_EXPAND;
con->enforce=1.0F;
con->type = CONSTRAINT_TYPE_TRACKTO;
data = (bTrackToConstraint *)
new_constraint_data(CONSTRAINT_TYPE_TRACKTO);
cti= get_constraint_typeinfo(CONSTRAINT_TYPE_TRACKTO);
cdata= MEM_callocN(cti->size, cti->structName);
cti->new_data(cdata);
data = (bTrackToConstraint *)cdata;
data->tar = ob->track;
data->reserved1 = ob->trackflag;
data->reserved2 = ob->upflag;
@ -5279,7 +5287,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
ob->track = 0;
}
ob = ob->id.next;
}
@ -6757,14 +6765,16 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
bArmature *arm;
ModifierData *md;
Object *ob;
for(arm= main->armature.first; arm; arm= arm->id.next)
arm->deformflag |= ARM_DEF_B_BONE_REST;
for(ob = main->object.first; ob; ob= ob->id.next)
for(md=ob->modifiers.first; md; md=md->next)
for(ob = main->object.first; ob; ob= ob->id.next) {
for(md=ob->modifiers.first; md; md=md->next) {
if(md->type==eModifierType_Armature)
((ArmatureModifierData*)md)->deformflag |= ARM_DEF_B_BONE_REST;
}
}
}
if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 5)) {
@ -6785,6 +6795,61 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
}
if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 7)) {
Object *ob;
bPoseChannel *pchan;
bConstraint *con;
bConstraintTarget *ct;
for(ob = main->object.first; ob; ob= ob->id.next) {
if(ob->pose) {
for(pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
for(con=pchan->constraints.first; con; con=con->next) {
if(con->type==CONSTRAINT_TYPE_PYTHON) {
bPythonConstraint *data= (bPythonConstraint *)con->data;
if (data->tar) {
/* version patching needs to be done */
ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget");
ct->tar = data->tar;
strcpy(ct->subtarget, data->subtarget);
ct->space = con->tarspace;
BLI_addtail(&data->targets, ct);
data->tarnum++;
/* clear old targets to avoid problems */
data->tar = NULL;
strcpy(data->subtarget, "");
}
}
}
}
}
for(con=ob->constraints.first; con; con=con->next) {
if(con->type==CONSTRAINT_TYPE_PYTHON) {
bPythonConstraint *data= (bPythonConstraint *)con->data;
if (data->tar) {
/* version patching needs to be done */
ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget");
ct->tar = data->tar;
strcpy(ct->subtarget, data->subtarget);
ct->space = con->tarspace;
BLI_addtail(&data->targets, ct);
data->tarnum++;
/* clear old targets to avoid problems */
data->tar = NULL;
strcpy(data->subtarget, "");
}
}
}
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
@ -7185,7 +7250,11 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
case CONSTRAINT_TYPE_PYTHON:
{
bPythonConstraint *data = (bPythonConstraint*)curcon->data;
expand_doit(fd, mainvar, data->tar);
bConstraintTarget *ct;
for (ct= data->targets.first; ct; ct= ct->next)
expand_doit(fd, mainvar, ct->tar);
expand_doit(fd, mainvar, data->text);
}
break;

@ -698,74 +698,27 @@ static void write_constraints(WriteData *wd, ListBase *conlist)
bConstraint *con;
for (con=conlist->first; con; con=con->next) {
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
/* Write the specific data */
switch (con->type) {
case CONSTRAINT_TYPE_NULL:
break;
case CONSTRAINT_TYPE_PYTHON:
{
bPythonConstraint *data = (bPythonConstraint*) con->data;
writestruct(wd, DATA, "bPythonConstraint", 1, data);
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
of library blocks that implement this.*/
IDP_WriteProperty(data->prop, wd);
if (cti && con->data) {
/* firstly, just write the plain con->data struct */
writestruct(wd, DATA, cti->structName, 1, con->data);
/* do any constraint specific stuff */
switch (con->type) {
case CONSTRAINT_TYPE_PYTHON:
{
bPythonConstraint *data = (bPythonConstraint*) con->data;
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
of library blocks that implement this.*/
IDP_WriteProperty(data->prop, wd);
}
break;
}
break;
case CONSTRAINT_TYPE_CHILDOF:
writestruct(wd, DATA, "bChildOfConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_TRACKTO:
writestruct(wd, DATA, "bTrackToConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_KINEMATIC:
writestruct(wd, DATA, "bKinematicConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_ROTLIKE:
writestruct(wd, DATA, "bRotateLikeConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_LOCLIKE:
writestruct(wd, DATA, "bLocateLikeConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_SIZELIKE:
writestruct(wd, DATA, "bSizeLikeConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_ACTION:
writestruct(wd, DATA, "bActionConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_LOCKTRACK:
writestruct(wd, DATA, "bLockTrackConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_FOLLOWPATH:
writestruct(wd, DATA, "bFollowPathConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_STRETCHTO:
writestruct(wd, DATA, "bStretchToConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_MINMAX:
writestruct(wd, DATA, "bMinMaxConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_LOCLIMIT:
writestruct(wd, DATA, "bLocLimitConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_ROTLIMIT:
writestruct(wd, DATA, "bRotLimitConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_SIZELIMIT:
writestruct(wd, DATA, "bSizeLimitConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
writestruct(wd, DATA, "bRigidBodyJointConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_CLAMPTO:
writestruct(wd, DATA, "bClampToConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_TRANSFORM:
writestruct(wd, DATA, "bTransformConstraint", 1, con->data);
break;
default:
break;
}
/* Write the constraint */
writestruct(wd, DATA, "bConstraint", 1, con);
}
@ -819,12 +772,12 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
for (md=modbase->first; md; md= md->next) {
ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti == NULL) return;
writestruct(wd, DATA, mti->structName, 1, md);
if (md->type==eModifierType_Hook) {
HookModifierData *hmd = (HookModifierData*) md;
writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar);
}
}

@ -61,9 +61,10 @@ char *get_con_subtarget_name(struct bConstraint *con, struct Object *target);
void rename_constraint(struct Object *ob, struct bConstraint *con, char *newname);
/* two special functions for PyConstraints */
/* a few special functions for PyConstraints */
char *buildmenu_pyconstraints(struct Text *con_text, int *pyconindex);
void validate_pyconstraint_cb(void *arg1, void *arg2);
void update_pyconstraint_cb(void *arg1, void *arg2);
/* two special functions for ChildOf Constriant */
void childof_const_setinv (void *conv, void *unused);

@ -86,7 +86,6 @@ extern int mod_moveDown(void *ob_v, void *md_v);
extern void const_moveUp(void *ob_v, void *con_v);
extern void const_moveDown(void *ob_v, void *con_v);
extern void del_constr_func (void *ob_v, void *con_v);
extern void get_constraint_typestring(char *str, void *con_v);
extern void get_constraint_ipo_context(void *ob_v, char *actname);
/* editing */

@ -36,13 +36,11 @@
#include "DNA_ID.h"
#include "DNA_ipo_types.h"
#include "DNA_listBase.h"
#include "DNA_object_types.h"
struct Action;
struct Text;
#ifndef __cplusplus
struct PyObject;
#endif
/* channels reside in Object or Action (ListBase) constraintChannels */
typedef struct bConstraintChannel {
@ -55,29 +53,67 @@ typedef struct bConstraintChannel {
/* A Constraint */
typedef struct bConstraint {
struct bConstraint *next, *prev;
void *data; /* Constraint data (a valid constraint type) */
short type; /* Constraint type */
short flag; /* Flag - General Settings */
char ownspace; /* Space that owner should be evaluated in */
char tarspace; /* Space that target should be evaluated in */
char tarspace; /* Space that target should be evaluated in (only used if 1 target) */
char name[30]; /* Constraint name */
char name[30]; /* Constraint name */
float enforce; /* Amount of influence exherted by constraint (0.0-1.0) */
} bConstraint;
/* Python Script Constraint */
typedef struct bPythonConstraint {
Object *tar; /* object to use as target (if required) */
char subtarget[32]; /* bone to use as subtarget (if required) */
/* Multiple-target constraints --------------------- */
/* This struct defines a constraint target.
* It is used during constraint solving regardless of how many targets the
* constraint has.
*/
typedef struct bConstraintTarget {
struct bConstraintTarget *next, *prev;
Object *tar; /* object to use as target */
char subtarget[32]; /* subtarget - pchan or vgroup name */
float matrix[4][4]; /* matrix used during constraint solving - should be cleared before each use */
short space; /* space that target should be evaluated in (overrides bConstraint->tarspace) */
short flag; /* runtime settings (for editor, etc.) */
short type; /* type of target (B_CONSTRAINT_OB_TYPE) */
short pad;
} bConstraintTarget;
/* bConstraintTarget -> flag */
typedef enum B_CONSTRAINT_TARGET_FLAG {
CONSTRAINT_TAR_TEMP = (1<<0), /* temporary target-struct that needs to be freed after use */
} B_CONSTRAINT_TARGET_FLAG;
/* bConstraintTarget/bConstraintOb -> type */
typedef enum B_CONSTRAINT_OB_TYPE {
CONSTRAINT_OBTYPE_OBJECT = 1, /* string is "" */
CONSTRAINT_OBTYPE_BONE, /* string is bone-name */
CONSTRAINT_OBTYPE_VERT, /* string is vertex-group name */
CONSTRAINT_OBTYPE_CV /* string is vertex-group name - is not available until curves get vgroups */
} B_CONSTRAINT_OB_TYPE;
/* Python Script Constraint */
typedef struct bPythonConstraint {
struct Text *text; /* text-buffer (containing script) to execute */
IDProperty *prop; /* 'id-properties' used to store custom properties for constraint */
int flag; /* general settings/state indicators accessed by bitmapping */
int pad;
int tarnum; /* number of targets - usually only 1-3 are needed */
ListBase targets; /* a list of targets that this constraint has (bConstraintTarget-s) */
Object *tar; /* target from previous implementation (version-patch sets this to NULL on file-load) */
char subtarget[32]; /* subtarger from previous implentation (version-patch sets this to "" on file-load) */
} bPythonConstraint;
/* Single-target subobject constraints --------------------- */
@ -125,10 +161,10 @@ typedef struct bLocateLikeConstraint {
typedef struct bMinMaxConstraint {
Object *tar;
int minmaxflag;
float offset;
int flag;
short sticky, stuck, pad1, pad2; /* for backward compatability */
float cache[3];
float offset;
int flag;
short sticky, stuck, pad1, pad2; /* for backward compatability */
float cache[3];
char subtarget[32];
} bMinMaxConstraint;
@ -143,13 +179,13 @@ typedef struct bSizeLikeConstraint {
/* Action Constraint */
typedef struct bActionConstraint {
Object *tar;
short type;
short type; /* what transform 'channel' drives the result */
short local; /* was used in versions prior to the Constraints recode */
int start;
int end;
int start;
int end;
float min;
float max;
int pad;
int pad;
struct bAction *act;
char subtarget[32];
} bActionConstraint;
@ -261,53 +297,73 @@ typedef struct bSizeLimitConstraint {
short pad1;
} bSizeLimitConstraint;
/* bConstraint.type */
#define CONSTRAINT_TYPE_NULL 0
#define CONSTRAINT_TYPE_CHILDOF 1 /* Unimplemented non longer :) - during constraints recode, Aligorith */
#define CONSTRAINT_TYPE_TRACKTO 2
#define CONSTRAINT_TYPE_KINEMATIC 3
#define CONSTRAINT_TYPE_FOLLOWPATH 4
#define CONSTRAINT_TYPE_ROTLIMIT 5 /* Unimplemented no longer :) - Aligorith */
#define CONSTRAINT_TYPE_LOCLIMIT 6 /* Unimplemented no longer :) - Aligorith */
#define CONSTRAINT_TYPE_SIZELIMIT 7 /* Unimplemented no longer :) - Aligorith */
#define CONSTRAINT_TYPE_ROTLIKE 8
#define CONSTRAINT_TYPE_LOCLIKE 9
#define CONSTRAINT_TYPE_SIZELIKE 10
#define CONSTRAINT_TYPE_PYTHON 11 /* Unimplemented no longer :) - Aligorith. Scripts */
#define CONSTRAINT_TYPE_ACTION 12
#define CONSTRAINT_TYPE_LOCKTRACK 13 /* New Tracking constraint that locks an axis in place - theeth */
#define CONSTRAINT_TYPE_DISTANCELIMIT 14 /* was never properly coded - removed! */
#define CONSTRAINT_TYPE_STRETCHTO 15 /* claiming this to be mine :) is in tuhopuu bjornmose */
#define CONSTRAINT_TYPE_MINMAX 16 /* floor constraint */
#define CONSTRAINT_TYPE_RIGIDBODYJOINT 17 /* rigidbody constraint */
#define CONSTRAINT_TYPE_CLAMPTO 18 /* clampto constraint */
#define CONSTRAINT_TYPE_TRANSFORM 19 /* transformation constraint */
/* ------------------------------------------ */
/* bConstraint->type
* - Do not ever change the order of these, or else files could get
* broken as their correct value cannot be resolved
*/
typedef enum B_CONSTAINT_TYPES {
CONSTRAINT_TYPE_NULL = 0, /* Invalid/legacy constraint */
CONSTRAINT_TYPE_CHILDOF, /* Unimplemented non longer :) - during constraints recode, Aligorith */
CONSTRAINT_TYPE_TRACKTO,
CONSTRAINT_TYPE_KINEMATIC,
CONSTRAINT_TYPE_FOLLOWPATH,
CONSTRAINT_TYPE_ROTLIMIT, /* Unimplemented no longer :) - Aligorith */
CONSTRAINT_TYPE_LOCLIMIT, /* Unimplemented no longer :) - Aligorith */
CONSTRAINT_TYPE_SIZELIMIT, /* Unimplemented no longer :) - Aligorith */
CONSTRAINT_TYPE_ROTLIKE,
CONSTRAINT_TYPE_LOCLIKE,
CONSTRAINT_TYPE_SIZELIKE,
CONSTRAINT_TYPE_PYTHON, /* Unimplemented no longer :) - Aligorith. Scripts */
CONSTRAINT_TYPE_ACTION,
CONSTRAINT_TYPE_LOCKTRACK, /* New Tracking constraint that locks an axis in place - theeth */
CONSTRAINT_TYPE_DISTANCELIMIT, /* was never properly coded - removed! */
CONSTRAINT_TYPE_STRETCHTO, /* claiming this to be mine :) is in tuhopuu bjornmose */
CONSTRAINT_TYPE_MINMAX, /* floor constraint */
CONSTRAINT_TYPE_RIGIDBODYJOINT, /* rigidbody constraint */
CONSTRAINT_TYPE_CLAMPTO, /* clampto constraint */
CONSTRAINT_TYPE_TRANSFORM, /* transformation (loc/rot/size -> loc/rot/size) constraint */
/* NOTE: everytime a new constraint is added, update this */
NUM_CONSTRAINT_TYPES= CONSTRAINT_TYPE_TRANSFORM
} B_CONSTRAINT_TYPES;
/* bConstraint->flag */
/* flags 0x2 (1<<1) and 0x8 (1<<3) were used in past */
/* flag 0x20 (1<<5) was used to indicate that a constraint was evaluated using a 'local' hack for posebones only */
typedef enum B_CONSTRAINT_FLAG {
/* expand for UI */
#define CONSTRAINT_EXPAND 0x01
CONSTRAINT_EXPAND = (1<<0),
/* pre-check for illegal object name or bone name */
#define CONSTRAINT_DISABLE 0x04
/* flags 0x2 and 0x8 were used in past, skip this */
/* to indicate which Ipo should be shown, maybe for 3d access later too */
#define CONSTRAINT_ACTIVE 0x10
/* flag 0x20 was used to indicate that a constraint was evaluated using a 'local' hack for posebones only */
CONSTRAINT_DISABLE = (1<<2),
/* to indicate which Ipo should be shown, maybe for 3d access later too */
CONSTRAINT_ACTIVE = (1<<4),
/* to indicate that the owner's space should only be changed into ownspace, but not out of it */
#define CONSTRAINT_SPACEONCE 0x40
CONSTRAINT_SPACEONCE = (1<<6)
} B_CONSTRAINT_FLAG;
/* bConstraint->ownspace/tarspace */
/* default for all - worldspace */
#define CONSTRAINT_SPACE_WORLD 0
/* for objects (relative to parent/without parent influence), for bones (along normals of bone, without parent/restposi) */
#define CONSTRAINT_SPACE_LOCAL 1
/* for posechannels - pose space */
#define CONSTRAINT_SPACE_POSE 2
/* for posechannels - local with parent */
#define CONSTRAINT_SPACE_PARLOCAL 3
typedef enum B_CONSTRAINT_SPACETYPES {
/* default for all - worldspace */
CONSTRAINT_SPACE_WORLD = 0,
/* for objects (relative to parent/without parent influence),
* for bones (along normals of bone, without parent/restpositions)
*/
CONSTRAINT_SPACE_LOCAL,
/* for posechannels - pose space */
CONSTRAINT_SPACE_POSE,
/* for posechannels - local with parent */
CONSTRAINT_SPACE_PARLOCAL,
} B_CONSTRAINT_SPACETYPES;
/* bConstraintChannel.flag */
#define CONSTRAINT_CHANNEL_SELECT 0x01
#define CONSTRAINT_CHANNEL_PROTECTED 0x02
typedef enum B_CONSTRAINTCHANNEL_FLAG {
CONSTRAINT_CHANNEL_SELECT = (1<<0),
CONSTRAINT_CHANNEL_PROTECTED = (1<<1)
} B_CONSTRAINTCHANNEL_FLAG;
/* -------------------------------------- */
/**
* The flags for ROTLIKE, LOCLIKE and SIZELIKE should be kept identical

@ -46,8 +46,10 @@ struct SpaceScript; /* DNA_space_types.h */
struct Script; /* BPI_script.h */
struct ScrArea; /* DNA_screen_types.h */
struct bScreen; /* DNA_screen_types.h */
struct bConstraint; /* DNA_constraint_types.h */
struct bPythonConstraint; /* DNA_constraint_types.h */
struct bConstraintOb; /* BKE_constraint.h */
struct bConstraintOb; /* DNA_constraint_types.h */
struct bConstraintTarget; /* DNA_constraint_types.h*/
#ifdef __cplusplus
extern "C" {
#endif
@ -71,10 +73,10 @@ extern "C" {
void BPy_Set_DrawButtonsList(void *list);
void BPy_Free_DrawButtonsList(void);
void BPY_pyconstraint_eval(struct bPythonConstraint *con, float ownermat[][4], float targetmat[][4]);
void BPY_pyconstraint_driver(struct bPythonConstraint *con, struct bConstraintOb *cob, struct Object *target, char subtarget[]);
void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
void BPY_pyconstraint_settings(void *arg1, void *arg2);
int BPY_pyconstraint_targets(struct bPythonConstraint *con, float targetmat[][4]);
void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct);
void BPY_pyconstraint_update(struct Object *owner, struct bConstraint *con);
int BPY_is_pyconstraint(struct Text *text);
void BPY_start_python( int argc, char **argv );

@ -45,6 +45,7 @@
#include "BKE_object.h" /* during_scriptlink() */
#include "BKE_text.h"
#include "BKE_constraint.h" /* for bConstraintOb */
#include "BKE_idprop.h"
#include "DNA_curve_types.h" /* for struct IpoDriver */
#include "DNA_ID.h" /* ipo driver */
@ -59,6 +60,7 @@
#include "BPI_script.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_armature.h"
#include "api2_2x/EXPP_interface.h"
#include "api2_2x/constant.h"
#include "api2_2x/gen_utils.h"
@ -1157,13 +1159,16 @@ static float pydriver_error(IpoDriver *driver) {
/********PyConstraints*********/
/* This function checks whether a text-buffer is a PyConstraint candidate.
* It uses simple text parsing that could be easily confused!
*/
int BPY_is_pyconstraint(Text *text)
{
TextLine *tline = text->lines.first;
if (tline && (tline->len > 10)) {
char *line = tline->line;
/* Expected format: #BPYCONSTRAINT
* The actual checks are forgiving, so slight variations also work. */
if (line && line[0] == '#' && strstr(line, "BPYCONSTRAINT")) return 1;
@ -1171,26 +1176,138 @@ int BPY_is_pyconstraint(Text *text)
return 0;
}
/* This function is called to update PyConstraint data so that it is compatible with the script.
* Some of the allocating/freeing of memory for constraint targets occurs here, espcially
* if the number of targets changes.
*/
void BPY_pyconstraint_update(Object *owner, bConstraint *con)
{
bPythonConstraint *data= con->data;
if (data->text) {
/* script does exist. it is assumed that this is a valid pyconstraint script */
PyObject *globals;
PyObject *retval, *gval;
int num;
/* clear the flag first */
data->flag = 0;
/* populate globals dictionary */
globals = CreateGlobalDictionary();
retval = RunPython(data->text, globals);
if (retval == NULL) {
BPY_Err_Handle(data->text->id.name);
ReleaseGlobalDictionary(globals);
data->flag |= PYCON_SCRIPTERROR;
return;
}
Py_XDECREF(retval);
retval = NULL;
/* try to find NUM_TARGETS */
gval = PyDict_GetItemString(globals, "NUM_TARGETS");
if ( (gval) && (num= PyInt_AsLong(gval)) ) {
/* NUM_TARGETS is defined... and non-zero */
bConstraintTarget *ct;
/* check if it is valid (just make sure it is not negative)
* TODO: PyInt_AsLong may return -1 as sign of invalid input...
*/
num = abs(num);
data->flag |= PYCON_USETARGETS;
/* check if the number of targets has changed */
if (num < data->tarnum) {
/* free a few targets */
for (ct=data->targets.last; num > -1; num--, ct=data->targets.last, data->tarnum--)
BLI_freelinkN(&data->targets, ct);
}
else if (num > data->tarnum) {
/* add a few targets */
for ( ; num > -1; num--, data->tarnum++) {
ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget");
BLI_addtail(&data->targets, ct);
}
}
/* validate targets */
for (ct= data->targets.first; ct; ct= ct->next) {
if (!exist_object(ct->tar)) {
ct->tar = NULL;
con->flag |= CONSTRAINT_DISABLE;
break;
}
if ( (ct->tar == owner) &&
(!get_named_bone(get_armature(owner), ct->subtarget)) )
{
con->flag |= CONSTRAINT_DISABLE;
break;
}
}
/* clear globals */
ReleaseGlobalDictionary(globals);
}
else {
/* NUM_TARGETS is not defined or equals 0 */
ReleaseGlobalDictionary(globals);
/* free all targets */
BLI_freelistN(&data->targets);
data->tarnum = 0;
data->flag &= ~PYCON_USETARGETS;
return;
}
}
else {
/* no script, so clear any settings/data now */
data->tarnum = 0;
data->flag = 0;
BLI_freelistN(&data->targets);
/* supposedly this should still leave the base struct... */
IDP_FreeProperty(data->prop);
}
}
/* PyConstraints Evaluation Function (only called from evaluate_constraint)
* This function is responsible for modifying the ownermat that it is passed.
*/
void BPY_pyconstraint_eval(bPythonConstraint *con, float ownermat[][4], float targetmat[][4])
void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase *targets)
{
PyObject *srcmat, *tarmat, *idprop;
PyObject *srcmat, *tarmat, *tarmats, *idprop;
PyObject *globals;
PyObject *gval;
PyObject *pyargs, *retval;
bConstraintTarget *ct;
MatrixObject *retmat;
int row, col;
int row, col, index;
if ( !con->text ) return;
if ( con->flag & PYCON_SCRIPTERROR) return;
if (!con->text) return;
if (con->flag & PYCON_SCRIPTERROR) return;
globals = CreateGlobalDictionary();
srcmat = newMatrixObject( (float*)ownermat, 4, 4, Py_NEW );
tarmat = newMatrixObject( (float*)targetmat, 4, 4, Py_NEW );
idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL);
/* wrap blender-data as PyObjects for evaluation
* - we expose the owner's matrix as pymatrix
* - id-properties are wrapped using the id-properties pyapi
* - targets are presented as a list of matrices
*/
srcmat = newMatrixObject((float *)cob->matrix, 4, 4, Py_NEW);
idprop = BPy_Wrap_IDProperty(NULL, con->prop, NULL);
tarmats= PyList_New(con->tarnum);
for (ct=targets->first, index=0; ct; ct=ct->next, index++) {
tarmat = newMatrixObject((float *)ct->matrix, 4, 4, Py_NEW);
PyList_SetItem(tarmats, index, tarmat);
}
/* since I can't remember what the armature weakrefs do, I'll just leave this here
commented out. This function was based on pydrivers, and it might still be relevent.
@ -1199,17 +1316,20 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, float ownermat[][4], float ta
return result;
}
*/
retval = RunPython( con->text, globals );
if ( retval == NULL ) {
BPY_Err_Handle(con->text->id.name);
ReleaseGlobalDictionary( globals );
con->flag |= PYCON_SCRIPTERROR;
retval = RunPython(con->text, globals);
if (retval == NULL) {
BPY_Err_Handle(con->text->id.name);
con->flag |= PYCON_SCRIPTERROR;
/* free temp objects */
Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
Py_XDECREF(idprop);
Py_XDECREF(srcmat);
Py_XDECREF(tarmats);
ReleaseGlobalDictionary(globals);
return;
}
@ -1218,29 +1338,34 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, float ownermat[][4], float ta
gval = PyDict_GetItemString(globals, "doConstraint");
if (!gval) {
ReleaseGlobalDictionary( globals );
/* free temp objects */
Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
printf("ERROR: no doConstraint function in constraint!\n");
/* free temp objects */
Py_XDECREF(idprop);
Py_XDECREF(srcmat);
Py_XDECREF(tarmats);
ReleaseGlobalDictionary(globals);
return;
}
/* Now for the fun part! Try and find the functions we need. */
if (PyFunction_Check(gval) ) {
pyargs = Py_BuildValue("OOO", srcmat, tarmat, idprop);
if (PyFunction_Check(gval)) {
pyargs = Py_BuildValue("OOO", srcmat, tarmats, idprop);
retval = PyObject_CallObject(gval, pyargs);
Py_XDECREF( pyargs );
} else {
Py_XDECREF(pyargs);
}
else {
printf("ERROR: doConstraint is supposed to be a function!\n");
con->flag |= PYCON_SCRIPTERROR;
ReleaseGlobalDictionary( globals );
Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
Py_XDECREF(idprop);
Py_XDECREF(srcmat);
Py_XDECREF(tarmats);
ReleaseGlobalDictionary(globals);
return;
}
@ -1249,11 +1374,12 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, float ownermat[][4], float ta
con->flag |= PYCON_SCRIPTERROR;
/* free temp objects */
ReleaseGlobalDictionary( globals );
Py_XDECREF(idprop);
Py_XDECREF(srcmat);
Py_XDECREF(tarmats);
ReleaseGlobalDictionary(globals);
Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
return;
}
@ -1261,177 +1387,78 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, float ownermat[][4], float ta
if (!PyObject_TypeCheck(retval, &matrix_Type)) {
printf("Error in PyConstraint - doConstraint: Function not returning a matrix!\n");
con->flag |= PYCON_SCRIPTERROR;
ReleaseGlobalDictionary( globals );
Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
Py_XDECREF( retval );
Py_XDECREF(idprop);
Py_XDECREF(srcmat);
Py_XDECREF(tarmats);
Py_XDECREF(retval);
ReleaseGlobalDictionary(globals);
return;
}
retmat = (MatrixObject*) retval;
retmat = (MatrixObject *)retval;
if (retmat->rowSize != 4 || retmat->colSize != 4) {
printf("Error in PyConstraint - doConstraint: Matrix returned is the wrong size!\n");
con->flag |= PYCON_SCRIPTERROR;
ReleaseGlobalDictionary( globals );
Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
Py_XDECREF( retval );
Py_XDECREF(idprop);
Py_XDECREF(srcmat);
Py_XDECREF(tarmats);
Py_XDECREF(retval);
ReleaseGlobalDictionary(globals);
return;
}
/* this is the reverse of code taken from newMatrix() */
for(row = 0; row < 4; row++) {
for(col = 0; col < 4; col++) {
ownermat[row][col] = retmat->contigPtr[row*4+col];
cob->matrix[row][col] = retmat->contigPtr[row*4+col];
}
}
/* clear globals */
ReleaseGlobalDictionary( globals );
/* free temp objects */
Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
Py_XDECREF( retval );
}
/* PyConstraints 'Driver' Function
* This function is responsible for running any code that requires full access to the owner and the target
* It should be used sparringly, and only for doing 'hacks' which are not possible any other way.
*/
void BPY_pyconstraint_driver(bPythonConstraint *con, bConstraintOb *cob, Object *target, char subtarget[])
{
PyObject *owner, *subowner, *tar, *subtar;
PyObject *idprop;
PyObject *globals, *gval;
PyObject *pyargs, *retval;
if ( !con->text ) return;
if ( con->flag & PYCON_SCRIPTERROR) return;
globals = CreateGlobalDictionary();
owner = Object_CreatePyObject( cob->ob );
subowner = PyPoseBone_FromPosechannel( cob->pchan );
tar = Object_CreatePyObject( target );
if ( (target) && (target->type==OB_ARMATURE) ) {
bPoseChannel *pchan;
pchan = get_pose_channel( target->pose, subtarget );
subtar = PyPoseBone_FromPosechannel( pchan );
}
else
subtar = PyString_FromString(subtarget);
idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL);
/* since I can't remember what the armature weakrefs do, I'll just leave this here
commented out. This function was based on pydrivers, and it might still be relevent.
if( !setup_armature_weakrefs()){
fprintf( stderr, "Oops - weakref dict setup\n");
return result;
}
*/
retval = RunPython( con->text, globals );
if ( retval == NULL ) {
BPY_Err_Handle(con->text->id.name);
ReleaseGlobalDictionary( globals );
con->flag |= PYCON_SCRIPTERROR;
/* free temp objects */
Py_XDECREF( idprop );
Py_XDECREF( owner );
Py_XDECREF( subowner );
Py_XDECREF( tar );
Py_XDECREF( subtar );
return;
}
if (retval) {Py_XDECREF( retval );}
retval = NULL;
gval = PyDict_GetItemString(globals, "doDriver");
if (!gval) {
ReleaseGlobalDictionary( globals );
/* free temp objects */
Py_XDECREF( idprop );
Py_XDECREF( owner );
Py_XDECREF( subowner );
Py_XDECREF( tar );
Py_XDECREF( subtar );
return;
}
/* Now for the fun part! Try and find the functions we need. */
if (PyFunction_Check(gval) ) {
pyargs = Py_BuildValue("OOOOO", owner, subowner, tar, subtar, idprop);
retval = PyObject_CallObject(gval, pyargs);
Py_XDECREF( pyargs );
} else {
printf("ERROR: doDriver is supposed to be a function!\n");
con->flag |= PYCON_SCRIPTERROR;
ReleaseGlobalDictionary( globals );
Py_XDECREF( idprop );
Py_XDECREF( owner );
Py_XDECREF( subowner );
Py_XDECREF( tar );
Py_XDECREF( subtar );
return;
}
/* an error occurred while running the function? */
if (!retval) {
BPY_Err_Handle(con->text->id.name);
con->flag |= PYCON_SCRIPTERROR;
}
Py_XDECREF(idprop);
Py_XDECREF(srcmat);
Py_XDECREF(tarmats);
Py_XDECREF(retval);
/* clear globals */
ReleaseGlobalDictionary( globals );
/* free temp objects */
Py_XDECREF( idprop );
Py_XDECREF( owner );
Py_XDECREF( subowner );
Py_XDECREF( tar );
Py_XDECREF( subtar );
ReleaseGlobalDictionary(globals);
}
/* This evaluates whether constraint uses targets, and also the target matrix
* Return code of 0 = doesn't use targets, 1 = uses targets + matrix set, -1 = uses targets + matrix not set
/* This evaluates the target matrix for each target the PyConstraint uses.
* NOTE: it only does one target at a time!
*/
int BPY_pyconstraint_targets(bPythonConstraint *con, float targetmat[][4])
void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
{
PyObject *tar, *subtar;
PyObject *tarmat, *idprop;
PyObject *globals;
PyObject *gval, *gval2;
PyObject *gval;
PyObject *pyargs, *retval;
MatrixObject *retmat;
int row, col;
if ( !con->text ) return 0;
if ( con->flag & PYCON_SCRIPTERROR) return 0;
if (!con->text) return;
if (con->flag & PYCON_SCRIPTERROR) return;
if (!ct) return;
globals = CreateGlobalDictionary();
tar = Object_CreatePyObject( con->tar );
if ( (con->tar) && (con->tar->type==OB_ARMATURE) ) {
tar = Object_CreatePyObject(ct->tar);
if ((ct->tar) && (ct->tar->type==OB_ARMATURE)) {
bPoseChannel *pchan;
pchan = get_pose_channel( con->tar->pose, con->subtarget );
subtar = PyPoseBone_FromPosechannel( pchan );
pchan = get_pose_channel(ct->tar->pose, ct->subtarget);
subtar = PyPoseBone_FromPosechannel(pchan);
}
else
subtar = PyString_FromString(con->subtarget);
subtar = PyString_FromString(ct->subtarget);
tarmat = newMatrixObject( (float*)targetmat, 4, 4, Py_NEW );
tarmat = newMatrixObject((float *)ct->matrix, 4, 4, Py_NEW);
idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL);
/* since I can't remember what the armature weakrefs do, I'll just leave this here
@ -1441,123 +1468,118 @@ int BPY_pyconstraint_targets(bPythonConstraint *con, float targetmat[][4])
return result;
}
*/
retval = RunPython( con->text, globals );
retval = RunPython(con->text, globals);
if ( retval == NULL ) {
if (retval == NULL) {
BPY_Err_Handle(con->text->id.name);
ReleaseGlobalDictionary( globals );
con->flag |= PYCON_SCRIPTERROR;
/* free temp objects */
Py_XDECREF( tar );
Py_XDECREF( subtar );
Py_XDECREF( idprop );
Py_XDECREF( tarmat );
return 0;
Py_XDECREF(tar);
Py_XDECREF(subtar);
Py_XDECREF(idprop);
Py_XDECREF(tarmat);
ReleaseGlobalDictionary(globals);
return;
}
Py_XDECREF( retval );
Py_XDECREF(retval);
retval = NULL;
/* try to find USE_TARGET global constant */
gval = PyDict_GetItemString(globals, "USE_TARGET");
if (!gval || PyObject_IsTrue(gval) != 1) {
ReleaseGlobalDictionary( globals );
/* free temp objects */
Py_XDECREF( tar );
Py_XDECREF( subtar );
Py_XDECREF( idprop );
Py_XDECREF( tarmat );
return 0;
}
/* try to find doTarget function to set the target matrix */
gval2 = PyDict_GetItemString(globals, "doTarget");
if (!gval2) {
ReleaseGlobalDictionary( globals );
gval = PyDict_GetItemString(globals, "doTarget");
if (!gval) {
/* free temp objects */
Py_XDECREF( tar );
Py_XDECREF( subtar );
Py_XDECREF( idprop );
Py_XDECREF( tarmat );
return -1;
Py_XDECREF(tar);
Py_XDECREF(subtar);
Py_XDECREF(idprop);
Py_XDECREF(tarmat);
ReleaseGlobalDictionary(globals);
return;
}
/* Now for the fun part! Try and find the functions we need.*/
if (PyFunction_Check(gval2) ) {
if (PyFunction_Check(gval)) {
pyargs = Py_BuildValue("OOOO", tar, subtar, tarmat, idprop);
retval = PyObject_CallObject(gval2, pyargs);
Py_XDECREF( pyargs );
} else {
retval = PyObject_CallObject(gval, pyargs);
Py_XDECREF(pyargs);
}
else {
printf("ERROR: doTarget is supposed to be a function!\n");
con->flag |= PYCON_SCRIPTERROR;
ReleaseGlobalDictionary( globals );
Py_XDECREF( tar );
Py_XDECREF( subtar );
Py_XDECREF( idprop );
Py_XDECREF( tarmat );
return -1;
Py_XDECREF(tar);
Py_XDECREF(subtar);
Py_XDECREF(idprop);
Py_XDECREF(tarmat);
ReleaseGlobalDictionary(globals);
return;
}
if (!retval) {
BPY_Err_Handle(con->text->id.name);
con->flag |= PYCON_SCRIPTERROR;
/* free temp objects */
ReleaseGlobalDictionary( globals );
Py_XDECREF( tar );
Py_XDECREF( subtar );
Py_XDECREF( idprop );
Py_XDECREF( tarmat );
return -1;
/* free temp objects */
Py_XDECREF(tar);
Py_XDECREF(subtar);
Py_XDECREF(idprop);
Py_XDECREF(tarmat);
ReleaseGlobalDictionary(globals);
return;
}
if (!PyObject_TypeCheck(retval, &matrix_Type)) {
ReleaseGlobalDictionary( globals );
con->flag |= PYCON_SCRIPTERROR;
Py_XDECREF( tar );
Py_XDECREF( subtar );
Py_XDECREF( idprop );
Py_XDECREF( tarmat );
Py_XDECREF( retval );
return -1;
Py_XDECREF(tar);
Py_XDECREF(subtar);
Py_XDECREF(idprop);
Py_XDECREF(tarmat);
Py_XDECREF(retval);
ReleaseGlobalDictionary(globals);
return;
}
retmat = (MatrixObject*) retval;
retmat = (MatrixObject *)retval;
if (retmat->rowSize != 4 || retmat->colSize != 4) {
printf("Error in PyConstraint - doTarget: Matrix returned is the wrong size!\n");
con->flag |= PYCON_SCRIPTERROR;
ReleaseGlobalDictionary( globals );
Py_XDECREF( tar );
Py_XDECREF( subtar );
Py_XDECREF( idprop );
Py_XDECREF( tarmat );
Py_XDECREF( retval );
return -1;
Py_XDECREF(tar);
Py_XDECREF(subtar);
Py_XDECREF(idprop);
Py_XDECREF(tarmat);
Py_XDECREF(retval);
ReleaseGlobalDictionary(globals);
return;
}
/* this is the reverse of code taken from newMatrix() */
for(row = 0; row < 4; row++) {
for(col = 0; col < 4; col++) {
targetmat[row][col] = retmat->contigPtr[row*4+col];
ct->matrix[row][col] = retmat->contigPtr[row*4+col];
}
}
/* clear globals */
ReleaseGlobalDictionary( globals );
/* free temp objects */
Py_XDECREF( tar );
Py_XDECREF( subtar );
Py_XDECREF( idprop );
Py_XDECREF( tarmat );
Py_XDECREF( retval );
return 1;
Py_XDECREF(tar);
Py_XDECREF(subtar);
Py_XDECREF(idprop);
Py_XDECREF(tarmat);
Py_XDECREF(retval);
/* clear globals */
ReleaseGlobalDictionary(globals);
}
/* This draws+handles the user-defined interface for editing pyconstraints idprops */
@ -1569,22 +1591,22 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
PyObject *gval;
PyObject *retval;
if ( !con->text ) return;
if ( con->flag & PYCON_SCRIPTERROR) return;
if (!con->text) return;
if (con->flag & PYCON_SCRIPTERROR) return;
globals = CreateGlobalDictionary();
idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL);
retval = RunPython( con->text, globals );
retval = RunPython(con->text, globals);
if ( retval == NULL ) {
if (retval == NULL) {
BPY_Err_Handle(con->text->id.name);
ReleaseGlobalDictionary( globals );
ReleaseGlobalDictionary(globals);
con->flag |= PYCON_SCRIPTERROR;
/* free temp objects */
Py_XDECREF( idprop );
Py_XDECREF(idprop);
return;
}
@ -1597,18 +1619,19 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
/* free temp objects */
ReleaseGlobalDictionary( globals );
Py_XDECREF( idprop );
Py_XDECREF(idprop);
return;
}
/* Now for the fun part! Try and find the functions we need. */
if (PyFunction_Check(gval) ) {
if (PyFunction_Check(gval)) {
retval = PyObject_CallFunction(gval, "O", idprop);
} else {
}
else {
printf("ERROR: getSettings is supposed to be a function!\n");
ReleaseGlobalDictionary( globals );
Py_XDECREF( idprop );
Py_XDECREF(idprop);
return;
}
@ -1617,17 +1640,17 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
con->flag |= PYCON_SCRIPTERROR;
/* free temp objects */
ReleaseGlobalDictionary( globals );
Py_XDECREF( idprop );
ReleaseGlobalDictionary(globals);
Py_XDECREF(idprop);
return;
}
else {
/* clear globals */
ReleaseGlobalDictionary( globals );
ReleaseGlobalDictionary(globals);
/* free temp objects */
Py_XDECREF( idprop );
Py_DECREF( retval );
Py_XDECREF(idprop);
Py_DECREF(retval);
return;
}
}

@ -534,7 +534,10 @@ static int constspace_setter( BPy_Constraint *self, int type, PyObject *value )
Object *tar;
char *subtarget;
tar= get_constraint_target(con, &subtarget);
// FIXME!!!
//tar= get_constraint_target(con, &subtarget);
tar = NULL;
subtarget = NULL;
/* only copy depending on target-type */
if (tar && subtarget[0]) {
@ -1318,10 +1321,11 @@ static PyObject *script_getter( BPy_Constraint * self, int type )
bPythonConstraint *con = (bPythonConstraint *)(self->con->data);
switch( type ) {
case EXPP_CONSTR_TARGET:
return Object_CreatePyObject( con->tar );
case EXPP_CONSTR_BONE:
return PyString_FromString( con->subtarget );
// FIXME!!!
//case EXPP_CONSTR_TARGET:
// return Object_CreatePyObject( con->tar );
//case EXPP_CONSTR_BONE:
// return PyString_FromString( con->subtarget );
case EXPP_CONSTR_SCRIPT:
return Text_CreatePyObject( con->text );
case EXPP_CONSTR_PROPS:
@ -1336,24 +1340,25 @@ static int script_setter( BPy_Constraint *self, int type, PyObject *value )
bPythonConstraint *con = (bPythonConstraint *)(self->con->data);
switch( type ) {
case EXPP_CONSTR_TARGET: {
Object *obj = (( BPy_Object * )value)->object;
if( !BPy_Object_Check( value ) )
return EXPP_ReturnIntError( PyExc_TypeError,
"expected BPy object argument" );
con->tar = obj;
return 0;
}
case EXPP_CONSTR_BONE: {
char *name = PyString_AsString( value );
if( !name )
return EXPP_ReturnIntError( PyExc_TypeError,
"expected string arg" );
BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
return 0;
}
// FIXME!!!
//case EXPP_CONSTR_TARGET: {
// Object *obj = (( BPy_Object * )value)->object;
// if( !BPy_Object_Check( value ) )
// return EXPP_ReturnIntError( PyExc_TypeError,
// "expected BPy object argument" );
// con->tar = obj;
// return 0;
// }
//case EXPP_CONSTR_BONE: {
// char *name = PyString_AsString( value );
// if( !name )
// return EXPP_ReturnIntError( PyExc_TypeError,
// "expected string arg" );
//
// BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
//
// return 0;
// }
case EXPP_CONSTR_SCRIPT: {
Text *text = (( BPy_Text * )value)->text;
if( !BPy_Object_Check( value ) )
@ -1852,14 +1857,20 @@ static int Constraint_compare( BPy_Constraint * a, BPy_Constraint * b )
static PyObject *Constraint_repr( BPy_Constraint * self )
{
char type[32];
bConstraintTypeInfo *cti;
if( !self->con )
return PyString_FromString( "[Constraint - Removed]");
get_constraint_typestring (type, self->con);
return PyString_FromFormat( "[Constraint \"%s\", Type \"%s\"]",
self->con->name, type );
if (!self->con)
return PyString_FromString("[Constraint - Removed]");
else
cti= constraint_get_typeinfo(self->con);
if (cti) {
return PyString_FromFormat("[Constraint \"%s\", Type \"%s\"]",
self->con->name, cti->name);
}
else {
return PyString_FromString("[Constraint \"%s\", Type \"Unknown\"]");
}
}
/* Three Python Constraint_Type helper functions needed by the Object module: */

File diff suppressed because it is too large Load Diff

@ -4285,10 +4285,10 @@ void draw_object(Base *base, int flag)
/* not for sets, duplicators or picking */
if(flag==0 && (!(G.vd->flag & V3D_HIDE_HELPLINES))) {
ListBase *list;
/* draw hook center and offset line */
if(ob!=G.obedit) draw_hooks(ob);
/* help lines and so */
if(ob!=G.obedit && ob->parent && (ob->parent->lay & G.vd->lay)) {
setlinestyle(3);
@ -4301,29 +4301,46 @@ void draw_object(Base *base, int flag)
/* Drawing the constraint lines */
list = &ob->constraints;
if (list){
/*
extern void make_axis_color(char *col, char *col2, char axis); // drawview.c
*/
if (list) {
bConstraint *curcon;
float tmat[4][4];
bConstraintOb *cob;
char col[4], col2[4];
BIF_GetThemeColor3ubv(TH_GRID, col);
make_axis_color(col, col2, 'z');
glColor3ubv((GLubyte *)col2);
for (curcon = list->first; curcon; curcon=curcon->next){
if ((curcon->flag & CONSTRAINT_EXPAND)&&(curcon->type!=CONSTRAINT_TYPE_NULL)&&(constraint_has_target(curcon))){
get_constraint_target_matrix(curcon, TARGET_OBJECT, NULL, tmat, bsystem_time(ob, (float)(G.scene->r.cfra), ob->sf));
setlinestyle(3);
glBegin(GL_LINES);
glVertex3fv(tmat[3]);
glVertex3fv(ob->obmat[3]);
glEnd();
setlinestyle(0);
cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
for (curcon = list->first; curcon; curcon=curcon->next) {
bConstraintTypeInfo *cti= constraint_get_typeinfo(curcon);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if ((curcon->flag & CONSTRAINT_EXPAND) && (cti->get_constraint_targets)) {
cti->get_constraint_targets(curcon, &targets);
for (ct= targets.first; ct; ct= ct->next) {
/* calculate target's matrix */
if (cti->get_target_matrix)
cti->get_target_matrix(curcon, cob, ct, bsystem_time(ob, (float)(G.scene->r.cfra), ob->sf));
else
Mat4One(ct->matrix);
setlinestyle(3);
glBegin(GL_LINES);
glVertex3fv(ct->matrix[3]);
glVertex3fv(ob->obmat[3]);
glEnd();
setlinestyle(0);
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(curcon, &targets, 1);
}
}
constraints_clear_evalob(cob);
}
}

@ -451,16 +451,28 @@ static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChann
pose= ob->pose;
for (pchant= pose->chanbase.first; pchant; pchant= pchant->next) {
for (con= pchant->constraints.first; con; con= con->next) {
Object *conOb;
char *subtarget;
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
conOb= get_constraint_target(con, &subtarget);
if (conOb == srcArm) {
if (strcmp(subtarget, "")==0)
set_constraint_target(con, tarArm, "");
else if (strcmp(pchan->name, subtarget)==0)
set_constraint_target(con, tarArm, curbone->name);
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
for (ct= targets.first; ct; ct= ct->next) {
if (ct->tar == srcArm) {
if (strcmp(ct->subtarget, "")==0) {
ct->tar = tarArm;
}
else if (strcmp(ct->subtarget, pchan->name)==0) {
ct->tar = tarArm;
strcpy(ct->subtarget, curbone->name);
}
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 0);
}
/* action constraint? */
@ -486,15 +498,28 @@ static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChann
/* fix object-level constraints */
if (ob != srcArm) {
for (con= ob->constraints.first; con; con= con->next) {
Object *conOb;
char *subtarget;
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
conOb= get_constraint_target(con, &subtarget);
if (conOb == srcArm) {
if (strcmp(subtarget, "")==0)
set_constraint_target(con, tarArm, "");
else if (strcmp(pchan->name, subtarget)==0)
set_constraint_target(con, tarArm, curbone->name);
/* constraint targets */
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
for (ct= targets.first; ct; ct= ct->next) {
if (ct->tar == srcArm) {
if (strcmp(ct->subtarget, "")==0) {
ct->tar = tarArm;
}
else if (strcmp(ct->subtarget, pchan->name)==0) {
ct->tar = tarArm;
strcpy(ct->subtarget, curbone->name);
}
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 0);
}
}
}

@ -156,10 +156,10 @@ bConstraint *get_active_constraint(Object *ob)
{
ListBase *lb= get_active_constraints(ob);
if(lb) {
if (lb) {
bConstraint *con;
for(con= lb->first; con; con=con->next)
if(con->flag & CONSTRAINT_ACTIVE)
for (con= lb->first; con; con=con->next)
if (con->flag & CONSTRAINT_ACTIVE)
return con;
}
return NULL;
@ -176,15 +176,15 @@ bConstraintChannel *get_active_constraint_channel(Object *ob)
bPoseChannel *pchan;
pchan = get_active_posechannel(ob);
if(pchan) {
for(con= pchan->constraints.first; con; con= con->next)
if(con->flag & CONSTRAINT_ACTIVE)
if (pchan) {
for (con= pchan->constraints.first; con; con= con->next)
if (con->flag & CONSTRAINT_ACTIVE)
break;
if(con) {
if (con) {
bActionChannel *achan = get_action_channel(ob->action, pchan->name);
if(achan) {
for(chan= achan->constraintChannels.first; chan; chan= chan->next)
if(!strcmp(chan->name, con->name))
if (achan) {
for (chan= achan->constraintChannels.first; chan; chan= chan->next)
if (!strcmp(chan->name, con->name))
break;
return chan;
}
@ -215,16 +215,26 @@ bConstraintChannel *get_active_constraint_channel(Object *ob)
bConstraint *add_new_constraint(short type)
{
bConstraint *con;
bConstraintTypeInfo *cti;
con = MEM_callocN(sizeof(bConstraint), "constraint");
/* Set up a generic constraint datablock */
con->type = type;
con->flag |= CONSTRAINT_EXPAND;
con->enforce=1.0F;
/* Load the data for it */
con->data = new_constraint_data(con->type);
con->enforce = 1.0F;
strcpy (con->name, "Const");
/* Load the data for it */
cti = constraint_get_typeinfo(con);
if (cti) {
con->data = MEM_callocN(cti->size, cti->structName);
/* only constraints that change any settings need this */
if (cti->new_data)
cti->new_data(con->data);
}
return con;
}
@ -246,24 +256,51 @@ void add_constraint_to_object(bConstraint *con, Object *ob)
char *get_con_subtarget_name(bConstraint *con, Object *target)
{
/*
* If the target for this constraint is target, return a pointer
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
static char subtarget[32];
/* If the target for this constraint is target, return a pointer
* to the name for this constraints subtarget ... NULL otherwise
*/
if (target == NULL)
return NULL;
if (constraint_has_target(con)) {
Object *tar;
char *subtarget;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
tar = get_constraint_target(con, &subtarget);
if (tar==target) return subtarget;
for (ct= targets.first; ct; ct= ct->next) {
if (ct->tar == target) {
if (ct->flag & CONSTRAINT_TAR_TEMP) {
/* as temporary targets were created, we can't point to thier subtarget,
* a local copy is made here... this should be ok as long as this function
* is not called twice with expectations that the string will stay the same
*/
strcpy(subtarget, ct->subtarget);
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 1);
return &(subtarget[0]);
}
else {
/* not temporary, so we can return a direct pointer to it */
return &(ct->subtarget[0]);
}
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 0);
}
return NULL;
}
/* checks validity of object pointers, and NULLs,
if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag */
* if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag
*/
static void test_constraints (Object *owner, const char* substring)
{
@ -279,29 +316,29 @@ static void test_constraints (Object *owner, const char* substring)
if (strlen (substring)) {
switch (owner->type) {
case OB_ARMATURE:
type = TARGET_BONE;
type = CONSTRAINT_OBTYPE_BONE;
break;
default:
type = TARGET_OBJECT;
type = CONSTRAINT_OBTYPE_OBJECT;
break;
}
}
else
type = TARGET_OBJECT;
type = CONSTRAINT_OBTYPE_OBJECT;
switch (type) {
case TARGET_OBJECT:
case CONSTRAINT_OBTYPE_OBJECT:
conlist = &owner->constraints;
break;
case TARGET_BONE:
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){
bone = get_named_bone( ((bArmature *)owner->data ), substring );
chan = get_pose_channel(owner->pose, substring);
if (bone && chan) {
conlist = &chan->constraints;
}
}
@ -317,7 +354,6 @@ static void test_constraints (Object *owner, const char* substring)
case CONSTRAINT_TYPE_PYTHON:
{
bPythonConstraint *data = curcon->data;
float dummy_matrix[4][4];
/* is there are valid script? */
if (!data->text) {
@ -328,35 +364,9 @@ static void test_constraints (Object *owner, const char* substring)
curcon->flag |= CONSTRAINT_DISABLE;
break;
}
data->flag &= ~PYCON_SCRIPTERROR;
/* does the constraint require target input? */
if (BPY_pyconstraint_targets(data, dummy_matrix))
data->flag |= PYCON_USETARGETS;
else
data->flag &= ~PYCON_USETARGETS;
/* check whether we have a valid target */
if (data->flag & PYCON_USETARGETS) {
/* validate target */
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;
}
}
else {
/* don't hold onto target */
data->tar = NULL;
BLI_strncpy(data->subtarget, "", 32);
}
/* does the constraint require target input... also validates targets */
BPY_pyconstraint_update(owner, curcon);
}
break;
case CONSTRAINT_TYPE_ACTION:
@ -630,6 +640,41 @@ void object_test_constraints (Object *owner)
}
/* 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)
{
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);
if (index < 0) {
if (abs(index) < num_targets)
index= num_targets - abs(index);
else
index= num_targets - 1;
}
else if (index >= num_targets) {
index= num_targets - 1;
}
for (ct=targets.first, i=0; ct; ct= ct->next, i++) {
if (i == index) {
ct->tar= target;
strcpy(ct->subtarget, subtarget);
break;
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 0);
}
}
/* context: active object in posemode, active channel, optional selected channel */
void add_constraint(int only_IK)
{
@ -768,11 +813,10 @@ void add_constraint(int only_IK)
}
else if (nr==18) {
char *menustr;
int scriptint= 0, dummy_int=0;
float dummy_matrix[4][4];
int scriptint= 0;
/* popup a list of usable scripts */
menustr = buildmenu_pyconstraints(NULL, &dummy_int);
menustr = buildmenu_pyconstraints(NULL, &scriptint);
scriptint = pupmenu(menustr);
MEM_freeN(menustr);
@ -783,11 +827,7 @@ void add_constraint(int only_IK)
validate_pyconstraint_cb(con->data, &scriptint);
/* make sure target allowance is set correctly */
dummy_int = BPY_pyconstraint_targets(con->data, dummy_matrix);
if (dummy_int) {
bPythonConstraint *pycon= (bPythonConstraint *)con->data;
pycon->flag |= PYCON_USETARGETS;
}
BPY_pyconstraint_update(ob, con);
}
}
else if (nr==19) {
@ -818,10 +858,10 @@ void add_constraint(int only_IK)
/* set the target */
if (pchansel) {
set_constraint_target(con, ob, pchansel->name);
set_constraint_nth_target(con, ob, pchansel->name, 0);
}
else if(obsel) {
set_constraint_target(con, obsel, NULL);
set_constraint_nth_target(con, obsel, NULL, 0);
}
else if (ELEM4(nr, 11, 13, 14, 15)==0) { /* add new empty as target */
Base *base= BASACT, *newbase;
@ -843,7 +883,7 @@ void add_constraint(int only_IK)
else
VECCOPY(obt->loc, ob->obmat[3]);
set_constraint_target(con, obt, NULL);
set_constraint_nth_target(con, obt, NULL, 0);
/* restore, add_object sets active */
BASACT= base;
@ -1011,6 +1051,16 @@ char *buildmenu_pyconstraints(Text *con_text, int *pyconindex)
return menustr;
}
/* this callback gets called when the 'refresh' button of a pyconstraint gets pressed */
void update_pyconstraint_cb(void *arg1, void *arg2)
{
Object *owner= (Object *)arg1;
bConstraint *con= (bConstraint *)arg2;
if (owner && con)
BPY_pyconstraint_update(owner, con);
}
/* ------------- Child-Of Constraint ------------------ */
/* ChildOf Constraint - set inverse callback */
@ -1047,7 +1097,7 @@ void childof_const_setinv (void *conv, void *unused)
/* do constraint solving on pose-matrix containing no transforms
* N.B. code is copied from armature.c (where_is_pose_bone)
*/
cob= constraints_make_evalob(ob, pchan, TARGET_BONE);
cob= constraints_make_evalob(ob, pchan, CONSTRAINT_OBTYPE_BONE);
solve_constraints(&pchan->constraints, cob, ctime);
constraints_clear_evalob(cob);

@ -1378,9 +1378,6 @@ void make_parent(void)
}
}
else if(par->type == OB_CURVE){
bConstraint *con;
bFollowPathConstraint *data;
mode= pupmenu("Make Parent %t|Normal Parent %x1|Follow Path %x2|Curve Deform %x3|Path Constraint %x4");
if(mode<=0){
return;
@ -1402,24 +1399,26 @@ void make_parent(void)
mode= PARSKEL;
}
else if(mode==4) {
bConstraint *con;
bFollowPathConstraint *data;
base= FIRSTBASE;
while(base) {
if TESTBASELIB(base) {
if(base!=BASACT) {
float cmat[4][4], vec[3];
con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
strcpy (con->name, "AutoPath");
data = con->data;
data->tar = BASACT->object;
add_constraint_to_object(con, base->object);
get_constraint_target_matrix(con, TARGET_OBJECT, NULL, cmat, G.scene->r.cfra - base->object->sf);
get_constraint_target_matrix(con, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, G.scene->r.cfra - base->object->sf);
VecSubf(vec, base->object->obmat[3], cmat[3]);
base->object->loc[0] = vec[0];
base->object->loc[1] = vec[1];
base->object->loc[2] = vec[2];

@ -286,7 +286,7 @@ static void do_text_filemenu(void *arg, int event)
case 1:
st->text= add_empty_text( "Text" );
st->top=0;
allqueue(REDRAWTEXT, 0);
allqueue(REDRAWHEADERS, 0);
break;
@ -313,36 +313,36 @@ static void do_text_filemenu(void *arg, int event)
break;
case 7:
{
Object *obt;
Object *ob;
bConstraint *con;
short update;
/* check all pyconstraints */
for (obt=G.main->object.first; obt; obt=obt->id.next) {
for (ob= G.main->object.first; ob; ob= ob->id.next) {
update = 0;
if(obt->type==OB_ARMATURE && obt->pose) {
if (ob->type==OB_ARMATURE && ob->pose) {
bPoseChannel *pchan;
for(pchan= obt->pose->chanbase.first; pchan; pchan= pchan->next) {
for (con = pchan->constraints.first; con; con=con->next) {
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
for (con = pchan->constraints.first; con; con= con->next) {
if (con->type==CONSTRAINT_TYPE_PYTHON) {
bPythonConstraint *data = con->data;
if (data->text==text) data->flag = 0;
if (data->text==text) BPY_pyconstraint_update(ob, con);
update = 1;
}
}
}
}
for (con = obt->constraints.first; con; con=con->next) {
for (con = ob->constraints.first; con; con= con->next) {
if (con->type==CONSTRAINT_TYPE_PYTHON) {
bPythonConstraint *data = con->data;
if (data->text==text) data->flag = 0;
if (data->text==text) BPY_pyconstraint_update(ob, con);
update = 1;
}
}
if (update) {
DAG_object_flush_update(G.scene, obt, OB_RECALC_DATA);
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
}
}
}

@ -600,10 +600,13 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
tenla1->name= "Constraints";
for(con= pchan->constraints.first; con; con= con->next, const_index++) {
ten1= outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
#if 0 /* disabled as it needs to be reworked for recoded constraints system */
target= get_constraint_target(con, &str);
if(str && str[0]) ten1->name= str;
else if(target) ten1->name= target->id.name+2;
else ten1->name= con->name;
#endif
ten1->name= con->name;
ten1->directdata= con;
/* possible add all other types links? */
}
@ -651,10 +654,13 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
tenla->name= "Constraints";
for(con= ob->constraints.first; con; con= con->next, a++) {
ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
#if 0 /* disabled due to constraints system targets recode... code here needs review */
target= get_constraint_target(con, &str);
if(str && str[0]) ten->name= str;
else if(target) ten->name= target->id.name+2;
else ten->name= con->name;
#endif
ten->name= con->name;
ten->directdata= con;
/* possible add all other types links? */
}

@ -329,23 +329,30 @@ void pose_select_constraint_target(void)
bConstraint *con;
/* paranoia checks */
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
if (!ob && !ob->pose) return;
if (ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if(arm->layer & pchan->bone->layer) {
if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
for(con= pchan->constraints.first; con; con= con->next) {
char *subtarget;
Object *target= get_constraint_target(con, &subtarget);
if (arm->layer & pchan->bone->layer) {
if (pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
for (con= pchan->constraints.first; con; con= con->next) {
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if(ob==target) {
if(subtarget) {
bPoseChannel *pchanc= get_pose_channel(ob->pose, subtarget);
if(pchanc)
pchanc->bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
for (ct= targets.first; ct; ct= ct->next) {
if ((ct->tar == ob) && (ct->subtarget[0])) {
bPoseChannel *pchanc= get_pose_channel(ob->pose, ct->subtarget);
if(pchanc)
pchanc->bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
}
}
if (cti->flush_constraint_targets)
cti->flush_constraint_targets(con, &targets, 1);
}
}
}