diff --git a/release/scripts/scripttemplate_pyconstraint.py b/release/scripts/scripttemplate_pyconstraint.py index 8dcc04360d0..68aa9194435 100644 --- a/release/scripts/scripttemplate_pyconstraint.py +++ b/release/scripts/scripttemplate_pyconstraint.py @@ -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 ''' diff --git a/source/blender/blenkernel/BKE_bad_level_calls.h b/source/blender/blenkernel/BKE_bad_level_calls.h index 296fd5837b5..32128c68af5 100644 --- a/source/blender/blenkernel/BKE_bad_level_calls.h +++ b/source/blender/blenkernel/BKE_bad_level_calls.h @@ -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 */ diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 7f7ea79fcc6..55a542f51d5 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -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 diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 39a3cf13087..40fd8c5ed18 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -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 diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c index 2524a804e53..9d00db8076d 100644 --- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c +++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c @@ -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 */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 10b2a364827..2030859000f 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.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 diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 020350d9e6f..b46504b0e6d 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -48,6 +48,7 @@ #include "DNA_meshdata_types.h" #include "DNA_lattice_types.h" #include "DNA_scene_types.h" +#include "DNA_text_types.h" #include "BKE_utildefines.h" #include "BKE_action.h" @@ -79,39 +80,18 @@ #endif -/* ********************* Data level ****************** */ - -void free_constraint_data (bConstraint *con) -{ - if (con->data) { - /* any constraint-type specific stuff here */ - switch (con->type) { - case CONSTRAINT_TYPE_PYTHON: - { - bPythonConstraint *data= con->data; - IDP_FreeProperty(data->prop); - MEM_freeN(data->prop); - } - break; - } - - MEM_freeN(con->data); - } -} - -void free_constraints (ListBase *conlist) -{ - bConstraint *con; - - /* Do any specific freeing */ - for (con=conlist->first; con; con=con->next) { - free_constraint_data(con); - } - - /* Free the whole list */ - BLI_freelistN(conlist); -} +/* ******************* Constraint Channels ********************** */ +/* Constraint Channels exist in one of two places: + * - Under Action Channels in an Action (act->chanbase->achan->constraintChannels) + * - Under Object without object-level action yet (ob->constraintChannels) + * + * The main purpose that constraint channels serve is to act as a link + * between an IPO-block which + */ +/* ------------ Data Management ----------- */ + +/* Free constraint channels, and reduce the number of users of the related ipo-blocks */ void free_constraint_channels (ListBase *chanbase) { bConstraintChannel *chan; @@ -125,27 +105,14 @@ void free_constraint_channels (ListBase *chanbase) BLI_freelistN(chanbase); } -void relink_constraints (struct ListBase *list) -{ - bConstraint *con; - - for (con = list->first; con; con=con->next) { - /* check if constraint has a target that needs relinking */ - if (constraint_has_target(con)) { - Object *tar; - char *subtarget; - - tar = get_constraint_target(con, &subtarget); - ID_NEW(tar); - } - } -} - +/* Make a copy of the constraint channels from dst to src, and also give the + * new constraint channels their own copy of the original's IPO. + */ void copy_constraint_channels (ListBase *dst, ListBase *src) { bConstraintChannel *dchan, *schan; - dst->first=dst->last=NULL; + dst->first = dst->last = NULL; duplicatelist(dst, src); for (dchan=dst->first, schan=src->first; dchan; dchan=dchan->next, schan=schan->next) { @@ -153,11 +120,14 @@ void copy_constraint_channels (ListBase *dst, ListBase *src) } } +/* Make a copy of the constraint channels from dst to src, but make the + * new constraint channels use the same IPO-data as their twin. + */ void clone_constraint_channels (ListBase *dst, ListBase *src) { bConstraintChannel *dchan, *schan; - dst->first=dst->last=NULL; + dst->first = dst->last = NULL; duplicatelist(dst, src); for (dchan=dst->first, schan=src->first; dchan; dchan=dchan->next, schan=schan->next) { @@ -165,354 +135,81 @@ void clone_constraint_channels (ListBase *dst, ListBase *src) } } -void copy_constraints (ListBase *dst, ListBase *src) +/* ------------- Constraint Channel Tools ------------ */ + +/* Find the constraint channel with a given name */ +bConstraintChannel *get_constraint_channel (ListBase *list, const char name[]) { - bConstraint *con, *srccon; + bConstraintChannel *chan; + + for (chan = list->first; chan; chan=chan->next) { + if (!strcmp(name, chan->name)) { + return chan; + } + } - dst->first= dst->last= NULL; - duplicatelist (dst, src); + return NULL; +} + +/* Find or create a new constraint channel */ +bConstraintChannel *verify_constraint_channel (ListBase *list, const char name[]) +{ + bConstraintChannel *chan; - for (con = dst->first, srccon=src->first; con; srccon=srccon->next, con=con->next) { - con->data = MEM_dupallocN (con->data); + chan= get_constraint_channel(list, name); + + if (chan == NULL) { + chan= MEM_callocN(sizeof(bConstraintChannel), "new constraint channel"); + BLI_addtail(list, chan); + strcpy(chan->name, name); + } + + return chan; +} + +/* --------- Constraint Channel Evaluation/Execution --------- */ + +/* IPO-system call: calculate IPO-block for constraint channels, and flush that + * info onto the corresponding constraint. + */ +void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, short onlydrivers) +{ + bConstraint *con; + bConstraintChannel *chan; + IpoCurve *icu= NULL; + + /* for each Constraint, calculate its Influence from the corresponding ConstraintChannel */ + for (con=conbase->first; con; con=con->next) { + chan = get_constraint_channel(chanbase, con->name); - /* only do specific constraints if required */ - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *pycon = (bPythonConstraint *)con->data; - bPythonConstraint *opycon = (bPythonConstraint *)srccon->data; + if (chan && chan->ipo) { + calc_ipo(chan->ipo, ctime); - pycon->prop = IDP_CopyProperty(opycon->prop); + for (icu=chan->ipo->curve.first; icu; icu=icu->next) { + if (!onlydrivers || icu->driver) { + switch (icu->adrcode) { + case CO_ENFORCE: + { + /* Influence is clamped to 0.0f -> 1.0f range */ + con->enforce = CLAMPIS(icu->curval, 0.0f, 1.0f); + } + break; + } + } + } } } } -/* **************** Editor Functions **************** */ +/* ************************ Constraints - General Utilities *************************** */ +/* These functions here don't act on any specific constraints, and are therefore should/will + * not require any of the special function-pointers afforded by the relevant constraint + * type-info structs. + */ -char constraint_has_target (bConstraint *con) -{ - switch (con->type) { - case CONSTRAINT_TYPE_PYTHON: - { - bPythonConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_TRACKTO: - { - bTrackToConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_KINEMATIC: - { - bKinematicConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_FOLLOWPATH: - { - bFollowPathConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_ROTLIKE: - { - bRotateLikeConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_LOCLIKE: - { - bLocateLikeConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_SIZELIKE: - { - bSizeLikeConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_MINMAX: - { - bMinMaxConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_ACTION: - { - bActionConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_LOCKTRACK: - { - bLockTrackConstraint *data = con->data; - if (data->tar) return 1; - } - case CONSTRAINT_TYPE_STRETCHTO: - { - bStretchToConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_RIGIDBODYJOINT: - { - bRigidBodyJointConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_CLAMPTO: - { - bClampToConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_CHILDOF: - { - bChildOfConstraint *data = con->data; - if (data->tar) return 1; - } - break; - case CONSTRAINT_TYPE_TRANSFORM: - { - bTransformConstraint *data = con->data; - if (data->tar) return 1; - } - break; - } - - /* Unknown types or CONSTRAINT_TYPE_NULL or no target */ - return 0; -} - -Object *get_constraint_target(bConstraint *con, char **subtarget) -{ - /* If the target for this constraint is target, return a pointer - * to the name for this constraints subtarget ... NULL otherwise - */ - switch (con->type) { - case CONSTRAINT_TYPE_PYTHON: - { - bPythonConstraint *data=con->data; - *subtarget = data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_ACTION: - { - bActionConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_LOCLIKE: - { - bLocateLikeConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_ROTLIKE: - { - bRotateLikeConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_SIZELIKE: - { - bSizeLikeConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_KINEMATIC: - { - bKinematicConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_TRACKTO: - { - bTrackToConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_MINMAX: - { - bMinMaxConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_LOCKTRACK: - { - bLockTrackConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_FOLLOWPATH: - { - bFollowPathConstraint *data = con->data; - *subtarget= NULL; - return data->tar; - } - break; - case CONSTRAINT_TYPE_STRETCHTO: - { - bStretchToConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_RIGIDBODYJOINT: - { - bRigidBodyJointConstraint *data = con->data; - *subtarget= NULL; - return data->tar; - } - break; - case CONSTRAINT_TYPE_CLAMPTO: - { - bClampToConstraint *data = con->data; - *subtarget= NULL; - return data->tar; - } - break; - case CONSTRAINT_TYPE_CHILDOF: - { - bChildOfConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - case CONSTRAINT_TYPE_TRANSFORM: - { - bTransformConstraint *data = con->data; - *subtarget= data->subtarget; - return data->tar; - } - break; - default: - *subtarget= NULL; - break; - } - - return NULL; -} - -void set_constraint_target(bConstraint *con, Object *ob, char *subtarget) -{ - /* Set the target for this constraint */ - switch (con->type) { - case CONSTRAINT_TYPE_PYTHON: - { - bPythonConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_ACTION: - { - bActionConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_LOCLIKE: - { - bLocateLikeConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_ROTLIKE: - { - bRotateLikeConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_SIZELIKE: - { - bSizeLikeConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_KINEMATIC: - { - bKinematicConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_TRACKTO: - { - bTrackToConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_LOCKTRACK: - { - bLockTrackConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_FOLLOWPATH: - { - bFollowPathConstraint *data = con->data; - data->tar= ob; - } - break; - case CONSTRAINT_TYPE_STRETCHTO: - { - bStretchToConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_RIGIDBODYJOINT: - { - bRigidBodyJointConstraint *data = con->data; - data->tar= ob; - } - break; - case CONSTRAINT_TYPE_MINMAX: - { - bMinMaxConstraint *data = (bMinMaxConstraint*)con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_CLAMPTO: - { - bClampToConstraint *data = con->data; - data->tar= ob; - } - break; - case CONSTRAINT_TYPE_CHILDOF: - { - bChildOfConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - case CONSTRAINT_TYPE_TRANSFORM: - { - bTransformConstraint *data = con->data; - data->tar= ob; - if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); - } - break; - } -} +/* -------------- Naming -------------- */ +/* Find the first available, non-duplicate name for a given constraint */ void unique_constraint_name (bConstraint *con, ListBase *list) { bConstraint *curcon; @@ -536,11 +233,11 @@ void unique_constraint_name (bConstraint *con, ListBase *list) } } - if (!exists) + if (exists == 0) return; /* Strip off the suffix */ - dot=strchr(con->name, '.'); + dot = strchr(con->name, '.'); if (dot) *dot=0; @@ -549,248 +246,21 @@ void unique_constraint_name (bConstraint *con, ListBase *list) exists = 0; for (curcon=list->first; curcon; curcon=curcon->next) { - if (con!=curcon) { - if (!strcmp(curcon->name, tempname)) { + if (con != curcon) { + if (strcmp(curcon->name, tempname)==0) { exists = 1; break; } } } - if (!exists) { + if (exists == 0) { strcpy(con->name, tempname); return; } } } -void *new_constraint_data (short type) -{ - void *result; - - switch (type) { - case CONSTRAINT_TYPE_PYTHON: - { - bPythonConstraint *data; - data = MEM_callocN(sizeof(bPythonConstraint), "pythonConstraint"); - - /* everything should be set correctly by calloc, except for the prop->type constant.*/ - data->prop = MEM_callocN(sizeof(IDProperty), "PyConstraintProps"); - data->prop->type = IDP_GROUP; - - result = data; - } - break; - case CONSTRAINT_TYPE_KINEMATIC: - { - bKinematicConstraint *data; - data = MEM_callocN(sizeof(bKinematicConstraint), "kinematicConstraint"); - - data->weight= (float)1.0; - data->orientweight= (float)1.0; - data->iterations = 500; - data->flag= CONSTRAINT_IK_TIP|CONSTRAINT_IK_STRETCH|CONSTRAINT_IK_POS; - - result = data; - } - break; - case CONSTRAINT_TYPE_TRACKTO: - { - bTrackToConstraint *data; - data = MEM_callocN(sizeof(bTrackToConstraint), "tracktoConstraint"); - - data->reserved1 = TRACK_Y; - data->reserved2 = UP_Z; - - result = data; - } - break; - case CONSTRAINT_TYPE_MINMAX: - { - bMinMaxConstraint *data; - data = MEM_callocN(sizeof(bMinMaxConstraint), "minmaxConstraint"); - - data->minmaxflag = TRACK_Z; - data->offset = 0.0f; - data->cache[0] = data->cache[1] = data->cache[2] = 0.0f; - data->flag = 0; - - result = data; - } - break; - case CONSTRAINT_TYPE_LOCLIKE: - { - bLocateLikeConstraint *data; - data = MEM_callocN(sizeof(bLocateLikeConstraint), "LocLikeConstraint"); - data->flag = LOCLIKE_X|LOCLIKE_Y|LOCLIKE_Z; - result = data; - } - break; - case CONSTRAINT_TYPE_ROTLIKE: - { - bRotateLikeConstraint *data; - data = MEM_callocN(sizeof(bRotateLikeConstraint), "RotLikeConstraint"); - data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z; - result = data; - } - break; - case CONSTRAINT_TYPE_SIZELIKE: - { - bSizeLikeConstraint *data; - data = MEM_callocN(sizeof(bLocateLikeConstraint), "SizeLikeConstraint"); - data->flag = SIZELIKE_X|SIZELIKE_Y|SIZELIKE_Z; - result = data; - } - break; - case CONSTRAINT_TYPE_ACTION: - { - bActionConstraint *data; - data = MEM_callocN(sizeof(bActionConstraint), "ActionConstraint"); - - /* set type to 20 (Loc X), as 0 is Rot X for backwards compatability */ - data->type = 20; - - result = data; - } - break; - case CONSTRAINT_TYPE_LOCKTRACK: - { - bLockTrackConstraint *data; - data = MEM_callocN(sizeof(bLockTrackConstraint), "locktrackConstraint"); - - data->trackflag = TRACK_Y; - data->lockflag = LOCK_Z; - - result = data; - } - break; - case CONSTRAINT_TYPE_FOLLOWPATH: - { - bFollowPathConstraint *data; - data = MEM_callocN(sizeof(bFollowPathConstraint), "followpathConstraint"); - - data->trackflag = TRACK_Y; - data->upflag = UP_Z; - data->offset = 0; - data->followflag = 0; - - result = data; - } - break; - case CONSTRAINT_TYPE_STRETCHTO: - { - bStretchToConstraint *data; - data = MEM_callocN(sizeof(bStretchToConstraint), "StretchToConstraint"); - - data->volmode = 0; - data->plane = 0; - data->orglength = 0.0; - data->bulge = 1.0; - result = data; - } - break; - case CONSTRAINT_TYPE_LOCLIMIT: - { - bLocLimitConstraint *data; - data = MEM_callocN(sizeof(bLocLimitConstraint), "LocLimitConstraint"); - result = data; - } - break; - case CONSTRAINT_TYPE_ROTLIMIT: - { - bRotLimitConstraint *data; - data = MEM_callocN(sizeof(bRotLimitConstraint), "RotLimitConstraint"); - result = data; - } - break; - case CONSTRAINT_TYPE_SIZELIMIT: - { - bSizeLimitConstraint *data; - data = MEM_callocN(sizeof(bSizeLimitConstraint), "SizeLimitConstraint"); - result = data; - } - break; - case CONSTRAINT_TYPE_RIGIDBODYJOINT: - { - bRigidBodyJointConstraint *data; - data = MEM_callocN(sizeof(bRigidBodyJointConstraint), "RigidBodyToConstraint"); - - // removed code which set target of this constraint - data->type=1; - - result = data; - } - break; - case CONSTRAINT_TYPE_CLAMPTO: - { - bClampToConstraint *data; - data = MEM_callocN(sizeof(bClampToConstraint), "ClampToConstraint"); - result = data; - } - break; - case CONSTRAINT_TYPE_CHILDOF: - { - bChildOfConstraint *data; - data = MEM_callocN(sizeof(bChildOfConstraint), "ChildOfConstraint"); - - data->flag = (CHILDOF_LOCX | CHILDOF_LOCY | CHILDOF_LOCZ | - CHILDOF_ROTX |CHILDOF_ROTY | CHILDOF_ROTZ | - CHILDOF_SIZEX | CHILDOF_SIZEY | CHILDOF_SIZEZ); - Mat4One(data->invmat); - - result = data; - } - break; - case CONSTRAINT_TYPE_TRANSFORM: - { - bTransformConstraint *data; - data = MEM_callocN(sizeof(bTransformConstraint), "TransformationConstraint"); - - data->map[0]= 0; - data->map[1]= 1; - data->map[2]= 2; - - result = data; - } - break; - - default: - result = NULL; - break; - } - - return result; -} - -bConstraintChannel *get_constraint_channel (ListBase *list, const char *name) -{ - bConstraintChannel *chan; - - for (chan = list->first; chan; chan=chan->next) { - if (!strcmp(name, chan->name)) { - return chan; - } - } - return NULL; -} - -/* finds or creates new constraint channel */ -bConstraintChannel *verify_constraint_channel (ListBase *list, const char *name) -{ - bConstraintChannel *chan; - - chan= get_constraint_channel(list, name); - - if(chan == NULL) { - chan= MEM_callocN(sizeof(bConstraintChannel), "new constraint chan"); - BLI_addtail(list, chan); - strcpy(chan->name, name); - } - - return chan; -} - - -/* ***************** Evaluating ********************* */ +/* ----------------- Evaluation Loop Preparation --------------- */ /* package an object/bone for use in constraint evaluation */ /* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */ @@ -803,7 +273,7 @@ bConstraintOb *constraints_make_evalob (Object *ob, void *subdata, short datatyp /* based on type of available data */ switch (datatype) { - case TARGET_OBJECT: + case CONSTRAINT_OBTYPE_OBJECT: { /* disregard subdata... calloc should set other values right */ if (ob) { @@ -817,7 +287,7 @@ bConstraintOb *constraints_make_evalob (Object *ob, void *subdata, short datatyp Mat4CpyMat4(cob->startmat, cob->matrix); } break; - case TARGET_BONE: + case CONSTRAINT_OBTYPE_BONE: { /* only set if we have valid bone, otherwise default */ if (ob && subdata) { @@ -835,7 +305,7 @@ bConstraintOb *constraints_make_evalob (Object *ob, void *subdata, short datatyp } break; - default: // other types not yet handled + default: /* other types not yet handled */ Mat4One(cob->matrix); Mat4One(cob->startmat); break; @@ -859,22 +329,28 @@ void constraints_clear_evalob (bConstraintOb *cob) /* copy matrices back to source */ switch (cob->type) { - case TARGET_OBJECT: + case CONSTRAINT_OBTYPE_OBJECT: { - /* copy new ob-matrix back to owner */ - Mat4CpyMat4(cob->ob->obmat, cob->matrix); - - /* copy inverse of delta back to owner */ - Mat4Invert(cob->ob->constinv, delta); + /* cob->ob might not exist! */ + if (cob->ob) { + /* copy new ob-matrix back to owner */ + Mat4CpyMat4(cob->ob->obmat, cob->matrix); + + /* copy inverse of delta back to owner */ + Mat4Invert(cob->ob->constinv, delta); + } } break; - case TARGET_BONE: + case CONSTRAINT_OBTYPE_BONE: { - /* copy new pose-matrix back to owner */ - Mat4MulMat4(cob->pchan->pose_mat, cob->matrix, cob->ob->imat); - - /* copy inverse of delta back to owner */ - Mat4Invert(cob->pchan->constinv, delta); + /* cob->ob or cob->pchan might not exist */ + if (cob->ob && cob->pchan) { + /* copy new pose-matrix back to owner */ + Mat4MulMat4(cob->pchan->pose_mat, cob->matrix, cob->ob->imat); + + /* copy inverse of delta back to owner */ + Mat4Invert(cob->pchan->constinv, delta); + } } break; } @@ -883,40 +359,7 @@ void constraints_clear_evalob (bConstraintOb *cob) MEM_freeN(cob); } -/* -------------------------------- Constraint Channels ---------------------------- */ - -/* does IPO's of constraint channels only */ -void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, int onlydrivers) -{ - bConstraint *con; - bConstraintChannel *chan; - IpoCurve *icu= NULL; - - /* for each Constraint, calculate its Influence from the corresponding ConstraintChannel */ - for (con=conbase->first; con; con=con->next) { - - chan = get_constraint_channel(chanbase, con->name); - - if (chan && chan->ipo) { - calc_ipo(chan->ipo, ctime); - - for (icu=chan->ipo->curve.first; icu; icu=icu->next) { - if(!onlydrivers || icu->driver) { - switch (icu->adrcode) { - case CO_ENFORCE: - { - /* Influence is clamped to 0.0f -> 1.0f range */ - con->enforce = CLAMPIS(icu->curval, 0.0f, 1.0f); - } - break; - } - } - } - } - } -} - -/* ------------------------------- Space-Conversion API ---------------------------- */ +/* -------------- Space-Conversion API -------------- */ /* This function is responsible for the correct transformations/conversions * of a matrix from one space to another for constraint evaluation. @@ -1112,7 +555,7 @@ void constraint_mat_convertspace (Object *ob, bPoseChannel *pchan, float mat[][4 } } -/* ------------------------------- Target ---------------------------- */ +/* ------------ General Target Matrix Tools ---------- */ /* function that sets the given matrix based on given vertex group in mesh */ static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4]) @@ -1311,18 +754,277 @@ static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][ } } +/* ************************* Specific Constraints ***************************** */ +/* Each constraint defines a set of functions, which will be called at the appropriate + * times. In addition to this, each constraint should have a type-info struct, where + * its functions are attached for use. + */ + +/* Template for type-info data: + * - make a copy of this when creating new constraints, and just change the functions + * pointed to as necessary + * - although the naming of functions doesn't matter, it would help for code + * readability, to follow the same naming convention as is presented here + * - any functions that a constraint doesn't need to define, don't define + * for such cases, just use NULL + * - these should be defined after all the functions have been defined, so that + * forward-definitions/prototypes don't need to be used! + * - keep this copy #if-def'd so that future constraints can get based off this + */ +#if 0 +static bConstraintTypeInfo CTI_CONSTRNAME = { + CONSTRAINT_TYPE_CONSTRNAME, /* type */ + sizeof(bConstrNameConstraint), /* size */ + "ConstrName", /* name */ + "bConstrNameConstraint", /* struct name */ + constrname_free, /* free data */ + constrname_relink, /* relink data */ + constrname_copy, /* copy data */ + constrname_new_data, /* new data */ + constrname_get_tars, /* get constraint targets */ + constrname_flush_tars, /* flush constraint targets */ + constrname_get_tarmat, /* get target matrix */ + constrname_evaluate /* evaluate */ +}; +#endif -/* stupid little cross product function, 0:x, 1:y, 2:z axes */ -static int basis_cross(int n, int m) +/* This function should be used for the get_target_matrix member of all + * constraints that are not picky about what happens to their target matrix. + */ +static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) { - if(n-m == 1) return 1; - if(n-m == -1) return -1; - if(n-m == 2) return -1; - if(n-m == -2) return 1; - else return 0; + if (VALID_CONS_TARGET(ct)) + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + else if (ct) + Mat4One(ct->matrix); } -static void vectomat(float *vec, float *target_up, short axis, short upflag, short flags, float m[][3]) +/* This following macro should be used for all standard single-target *_get_tars functions + * to save typing and reduce maintainance woes. + * (Hopefully all compilers will be happy with the lines with just a space on them. Those are + * really just to help this code easier to read) + */ +#define SINGLETARGET_GET_TARS(con, data, ct, list) \ + { \ + ct= MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \ + \ + ct->tar= data->tar; \ + strcpy(ct->subtarget, data->subtarget); \ + ct->space= con->tarspace; \ + ct->flag= CONSTRAINT_TAR_TEMP; \ + \ + if (ct->tar) { \ + if ((ct->tar->type==OB_ARMATURE) && (ct->subtarget[0])) ct->type = CONSTRAINT_OBTYPE_BONE; \ + else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) ct->type = CONSTRAINT_OBTYPE_VERT; \ + else ct->type = CONSTRAINT_OBTYPE_OBJECT; \ + } \ + \ + BLI_addtail(list, ct); \ + } + +/* This following macro should be used for all standard single-target *_get_tars functions + * to save typing and reduce maintainance woes. It does not do the subtarget related operations + * (Hopefully all compilers will be happy with the lines with just a space on them. Those are + * really just to help this code easier to read) + */ +#define SINGLETARGETNS_GET_TARS(con, data, ct, list) \ + { \ + ct= MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \ + \ + ct->tar= data->tar; \ + ct->space= con->tarspace; \ + ct->flag= CONSTRAINT_TAR_TEMP; \ + \ + if (ct->tar) ct->type = CONSTRAINT_OBTYPE_OBJECT; \ + \ + BLI_addtail(list, ct); \ + } + +/* This following macro should be used for all standard single-target *_flush_tars functions + * to save typing and reduce maintainance woes. + * (Hopefully all compilers will be happy with the lines with just a space on them. Those are + * really just to help this code easier to read) + */ +#define SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) \ + { \ + if (ct) { \ + if (nocopy == 0) { \ + data->tar= ct->tar; \ + strcpy(data->subtarget, ct->subtarget); \ + con->tarspace= ct->space; \ + } \ + \ + BLI_freelistN(list); \ + } \ + } + +/* This following macro should be used for all standard single-target *_flush_tars functions + * to save typing and reduce maintainance woes. It does not do the subtarget related operations + * (Hopefully all compilers will be happy with the lines with just a space on them. Those are + * really just to help this code easier to read) + */ +#define SINGLETARGETNS_FLUSH_TARS(con, data, ct, list, nocopy) \ + { \ + if (ct) { \ + if (nocopy == 0) { \ + data->tar= ct->tar; \ + con->tarspace= ct->space; \ + } \ + \ + BLI_freelistN(list); \ + } \ + } + +/* --------- ChildOf Constraint ------------ */ + +static void childof_new_data (void *cdata) +{ + bChildOfConstraint *data= (bChildOfConstraint *)cdata; + + data->flag = (CHILDOF_LOCX | CHILDOF_LOCY | CHILDOF_LOCZ | + CHILDOF_ROTX |CHILDOF_ROTY | CHILDOF_ROTZ | + CHILDOF_SIZEX | CHILDOF_SIZEY | CHILDOF_SIZEZ); + Mat4One(data->invmat); +} + +static void childof_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bChildOfConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} + +static void childof_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bChildOfConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void childof_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bChildOfConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float parmat[4][4], invmat[4][4], tempmat[4][4]; + float loc[3], eul[3], size[3]; + float loco[3], eulo[3], sizo[3]; + + /* get offset (parent-inverse) matrix */ + Mat4CpyMat4(invmat, data->invmat); + + /* extract components of both matrices */ + VECCOPY(loc, ct->matrix[3]); + Mat4ToEul(ct->matrix, eul); + Mat4ToSize(ct->matrix, size); + + VECCOPY(loco, invmat[3]); + Mat4ToEul(invmat, eulo); + Mat4ToSize(invmat, sizo); + + /* disable channels not enabled */ + if (!(data->flag & CHILDOF_LOCX)) loc[0]= loco[0]= 0.0f; + if (!(data->flag & CHILDOF_LOCY)) loc[1]= loco[1]= 0.0f; + if (!(data->flag & CHILDOF_LOCZ)) loc[2]= loco[2]= 0.0f; + if (!(data->flag & CHILDOF_ROTX)) eul[0]= eulo[0]= 0.0f; + if (!(data->flag & CHILDOF_ROTY)) eul[1]= eulo[1]= 0.0f; + if (!(data->flag & CHILDOF_ROTZ)) eul[2]= eulo[2]= 0.0f; + if (!(data->flag & CHILDOF_SIZEX)) size[0]= sizo[0]= 1.0f; + if (!(data->flag & CHILDOF_SIZEY)) size[1]= sizo[1]= 1.0f; + if (!(data->flag & CHILDOF_SIZEZ)) size[2]= sizo[2]= 1.0f; + + /* make new target mat and offset mat */ + LocEulSizeToMat4(ct->matrix, loc, eul, size); + LocEulSizeToMat4(invmat, loco, eulo, sizo); + + /* multiply target (parent matrix) by offset (parent inverse) to get + * the effect of the parent that will be exherted on the owner + */ + Mat4MulMat4(parmat, invmat, ct->matrix); + + /* now multiply the parent matrix by the owner matrix to get the + * the effect of this constraint (i.e. owner is 'parented' to parent) + */ + Mat4CpyMat4(tempmat, cob->matrix); + Mat4MulMat4(cob->matrix, tempmat, parmat); + } +} + +static bConstraintTypeInfo CTI_CHILDOF = { + CONSTRAINT_TYPE_CHILDOF, /* type */ + sizeof(bChildOfConstraint), /* size */ + "ChildOf", /* name */ + "bChildOfConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + childof_new_data, /* new data */ + childof_get_tars, /* get constraint targets */ + childof_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get a target matrix */ + childof_evaluate /* evaluate */ +}; + +/* -------- TrackTo Constraint ------- */ + +static void trackto_new_data (void *cdata) +{ + bTrackToConstraint *data= (bTrackToConstraint *)cdata; + + data->reserved1 = TRACK_Y; + data->reserved2 = UP_Z; +} + +static void trackto_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bTrackToConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} + +static void trackto_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bTrackToConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + + +static int basis_cross (int n, int m) +{ + switch (n-m) { + case 1: + case -2: + return 1; + + case -1: + case 2: + return -1; + + default: + return 0; + } +} + +static void vectomat (float *vec, float *target_up, short axis, short upflag, short flags, float m[][3]) { float n[3]; float u[3]; /* vector specifying the up axis */ @@ -1332,17 +1034,16 @@ static void vectomat(float *vec, float *target_up, short axis, short upflag, sho int right_index; VecCopyf(n, vec); - if(Normalize(n) == 0.0) { + if (Normalize(n) == 0.0) { n[0] = 0.0; n[1] = 0.0; n[2] = 1.0; } - if(axis > 2) axis -= 3; + if (axis > 2) axis -= 3; else VecMulf(n,-1); /* n specifies the transformation of the track axis */ - - if(flags & TARGET_Z_UP) { + if (flags & TARGET_Z_UP) { /* target Z axis is the global up axis */ u[0] = target_up[0]; u[1] = target_up[1]; @@ -1360,7 +1061,7 @@ static void vectomat(float *vec, float *target_up, short axis, short upflag, sho VecSubf(proj, u, proj); /* then onto the plane */ /* proj specifies the transformation of the up axis */ - if(Normalize(proj) == 0.0) { /* degenerate projection */ + if (Normalize(proj) == 0.0) { /* degenerate projection */ proj[0] = 0.0; proj[1] = 1.0; proj[2] = 0.0; @@ -1370,19 +1071,19 @@ static void vectomat(float *vec, float *target_up, short axis, short upflag, sho Crossf(right, proj, n); Normalize(right); - if(axis != upflag) { + if (axis != upflag) { right_index = 3 - axis - upflag; - neg = (float) basis_cross(axis, upflag); - + neg = (float)basis_cross(axis, upflag); + /* account for up direction, track direction */ m[right_index][0] = neg * right[0]; m[right_index][1] = neg * right[1]; m[right_index][2] = neg * right[2]; - + m[upflag][0] = proj[0]; m[upflag][1] = proj[1]; m[upflag][2] = proj[2]; - + m[axis][0] = n[0]; m[axis][1] = n[1]; m[axis][2] = n[2]; @@ -1397,1449 +1098,2209 @@ static void vectomat(float *vec, float *target_up, short axis, short upflag, sho } -/* called during solve_constraints */ -/* also for make_parent, to find correct inverse of "follow path" */ -/* warning: ownerdata is PoseChannel or Object */ -/* ctime is global time, uncorrected for local bsystem_time */ -short get_constraint_target_matrix (bConstraint *con, short ownertype, void *ownerdata, float mat[][4], float ctime) +static void trackto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) { - short valid=0; - - switch (con->type) { - case CONSTRAINT_TYPE_NULL: - { - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_ACTION: - { - if (ownertype == TARGET_BONE) { - extern void chan_calc_mat(bPoseChannel *chan); - bActionConstraint *data = (bActionConstraint*)con->data; - bPose *pose; - bPoseChannel *pchan, *tchan; - float tempmat[4][4], vec[3]; - float s, t; - short axis; - - /* initialise return matrix */ - Mat4One(mat); - - /* only continue if there is a target */ - if (data->tar==NULL) return 0; - - /* get the transform matrix of the target */ - constraint_target_to_mat4(data->tar, data->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, con->tarspace); // FIXME: change these spaces - - /* determine where in transform range target is */ - /* data->type is mapped as follows for backwards compatability: - * 00,01,02 - rotation (it used to be like this) - * 10,11,12 - scaling - * 20,21,22 - location - */ - if (data->type < 10) { - /* extract rotation (is in whatever space target should be in) */ - Mat4ToEul(tempmat, vec); - vec[0] *= (float)(180.0/M_PI); - vec[1] *= (float)(180.0/M_PI); - vec[2] *= (float)(180.0/M_PI); - axis= data->type; - } - else if (data->type < 20) { - /* extract scaling (is in whatever space target should be in) */ - Mat4ToSize(tempmat, vec); - axis= data->type - 10; - } - else { - /* extract location */ - VECCOPY(vec, tempmat[3]); - axis= data->type - 20; - } - - /* Target defines the animation */ - s = (vec[axis]-data->min) / (data->max-data->min); - CLAMP(s, 0, 1); - t = ( s * (data->end-data->start)) + data->start; - - /* Get the appropriate information from the action, we make temp pose */ - pose = MEM_callocN(sizeof(bPose), "pose"); - - pchan = ownerdata; - tchan= verify_pose_channel(pose, pchan->name); - extract_pose_from_action(pose, data->act, t); - - chan_calc_mat(tchan); - - Mat4CpyMat4(mat, tchan->chan_mat); - - /* Clean up */ - free_pose_channels(pose); - MEM_freeN(pose); - } - } - break; - case CONSTRAINT_TYPE_LOCLIKE: - { - bLocateLikeConstraint *data = (bLocateLikeConstraint*)con->data; - Object *ob= data->tar; - - if (data->tar) { - if (data->tar->type==OB_ARMATURE && strlen(data->subtarget)) { - /* Pose-Channels for the CopyLoc target are handled specially, so that - * we can support using the bone-tip as an option. - */ - bPoseChannel *pchan; - float tmat[4][4]; - - pchan = get_pose_channel(ob->pose, data->subtarget); - if (pchan) { - Mat4CpyMat4(tmat, pchan->pose_mat); - - if (data->flag & LOCLIKE_TIP) { - VECCOPY(tmat[3], pchan->pose_tail); - } - - Mat4MulMat4(mat, tmat, ob->obmat); - } - else - Mat4CpyMat4(mat, ob->obmat); - - /* convert matrix space as required */ - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - } - else { - /* get target matrix as is done normally for other constraints */ - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - } - valid=1; - } - else - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_ROTLIKE: - { - bRotateLikeConstraint *data; - data = (bRotateLikeConstraint*)con->data; - - if (data->tar) { - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - valid=1; - } - else - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_SIZELIKE: - { - bSizeLikeConstraint *data; - data = (bSizeLikeConstraint*)con->data; - - if (data->tar) { - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - valid=1; - } - else - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_MINMAX: - { - bMinMaxConstraint *data = (bMinMaxConstraint*)con->data; - - if (data->tar) { - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - valid=1; - } - else - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_TRACKTO: - { - bTrackToConstraint *data; - data = (bTrackToConstraint*)con->data; - - if (data->tar) { - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - valid=1; - } - else - Mat4One (mat); - } - break; - case CONSTRAINT_TYPE_KINEMATIC: - { - bKinematicConstraint *data; - data = (bKinematicConstraint*)con->data; - - if (data->tar) { - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - valid=1; - } - else if (data->flag & CONSTRAINT_IK_AUTO) { - Object *ob= (Object *)ownerdata; - - if (ob==NULL) - Mat4One(mat); - else { - float vec[3]; - /* move grabtarget into world space */ - VECCOPY(vec, data->grabtarget); - Mat4MulVecfl(ob->obmat, vec); - Mat4CpyMat4(mat, ob->obmat); - VECCOPY(mat[3], vec); - } - } - else - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_LOCKTRACK: - { - bLockTrackConstraint *data; - data = (bLockTrackConstraint*)con->data; - - if (data->tar) { - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - valid=1; - } - else - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_FOLLOWPATH: - { - bFollowPathConstraint *data; - data = (bFollowPathConstraint*)con->data; - - if (data->tar) { - Curve *cu; - float q[4], vec[4], dir[3], *quat, x1; - float totmat[4][4]; - float curvetime; - - Mat4One(totmat); - Mat4One(mat); - - cu= data->tar->data; - - /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, - currently for paths to work it needs to go through the bevlist/displist system (ton) */ - - if (cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */ - makeDispListCurveTypes(data->tar, 0); - if (cu->path && cu->path->data) { - curvetime= bsystem_time(data->tar, (float)ctime, 0.0) - data->offset; - - if (calc_ipo_spec(cu->ipo, CU_SPEED, &curvetime)==0) { - curvetime /= cu->pathlen; - CLAMP(curvetime, 0.0, 1.0); - } - - if (where_on_path(data->tar, curvetime, vec, dir) ) { - if (data->followflag) { - quat= vectoquat(dir, (short) data->trackflag, (short) data->upflag); - - Normalize(dir); - q[0]= (float)cos(0.5*vec[3]); - x1= (float)sin(0.5*vec[3]); - q[1]= -x1*dir[0]; - q[2]= -x1*dir[1]; - q[3]= -x1*dir[2]; - QuatMul(quat, q, quat); - - QuatToMat4(quat, totmat); - } - VECCOPY(totmat[3], vec); - - Mat4MulSerie(mat, data->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL); - } - } - valid=1; - } - else - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_STRETCHTO: - { - bStretchToConstraint *data; - data = (bStretchToConstraint*)con->data; - - if (data->tar) { - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - valid = 1; - } - else - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_PYTHON: - { - bPythonConstraint *data; - data = (bPythonConstraint*)con->data; - - /* special exception for curves - depsgraph issues */ - if (data->tar && data->tar->type == OB_CURVE) { - Curve *cu= data->tar->data; - - /* this check is to make sure curve objects get updated on file load correctly.*/ - if (cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */ - makeDispListCurveTypes(data->tar, 0); - } - - /* if the script doesn't set the target matrix for any reason, fall back to standard methods */ - if (data->tar) { - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - if (BPY_pyconstraint_targets(data, mat) >= 1) { - valid = 1; - } - } - if (!valid) - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_CLAMPTO: - { - bClampToConstraint *data; - data = (bClampToConstraint*)con->data; - - if (data->tar) { - Curve *cu= data->tar->data; - - /* note; when creating constraints that follow path, the curve gets the CU_PATH set now, - currently for paths to work it needs to go through the bevlist/displist system (ton) */ - - if (cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */ - makeDispListCurveTypes(data->tar, 0); - - valid = 1; - } - - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_CHILDOF: - { - bChildOfConstraint *data; - data= (bChildOfConstraint *)con->data; - - if (data->tar) { - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - valid = 1; - } - else - Mat4One(mat); - } - break; - case CONSTRAINT_TYPE_TRANSFORM: - { - bTransformConstraint *data; - data= (bTransformConstraint *)con->data; - - if (data->tar) { - constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); - valid = 1; - } - else - Mat4One(mat); - } - break; - - default: - Mat4One(mat); - break; + bTrackToConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float size[3], vec[3]; + float totmat[3][3]; + float tmat[4][4]; + + /* Get size property, since ob->size is only the object's own relative size, not its global one */ + Mat4ToSize(cob->matrix, size); + + /* Clear the object's rotation */ + cob->matrix[0][0]=size[0]; + cob->matrix[0][1]=0; + cob->matrix[0][2]=0; + cob->matrix[1][0]=0; + cob->matrix[1][1]=size[1]; + cob->matrix[1][2]=0; + cob->matrix[2][0]=0; + cob->matrix[2][1]=0; + cob->matrix[2][2]=size[2]; + + /* targetmat[2] instead of ownermat[2] is passed to vectomat + * for backwards compatability it seems... (Aligorith) + */ + VecSubf(vec, cob->matrix[3], ct->matrix[3]); + vectomat(vec, ct->matrix[2], + (short)data->reserved1, (short)data->reserved2, + data->flags, totmat); + + Mat4CpyMat4(tmat, cob->matrix); + Mat4MulMat34(cob->matrix, totmat, tmat); } - - return valid; } -/* ---------------------------------------------- Constraint Evaluation ------------------------------------------------- */ +static bConstraintTypeInfo CTI_TRACKTO = { + CONSTRAINT_TYPE_TRACKTO, /* type */ + sizeof(bTrackToConstraint), /* size */ + "TrackTo", /* name */ + "bTrackToConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + trackto_new_data, /* new data */ + trackto_get_tars, /* get constraint targets */ + trackto_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + trackto_evaluate /* evaluate */ +}; -/* This is only called during solve_constraints to solve a particular constraint. - * It works on ownermat, and uses targetmat to help accomplish its tasks. - */ -static void evaluate_constraint (bConstraint *constraint, float ownermat[][4], float targetmat[][4]) +/* --------- Inverse-Kinemetics --------- */ + +static void kinematic_new_data (void *cdata) { - if (constraint == NULL || constraint->data == NULL) - return; + bKinematicConstraint *data= (bKinematicConstraint *)cdata; + + data->weight= (float)1.0; + data->orientweight= (float)1.0; + data->iterations = 500; + data->flag= CONSTRAINT_IK_TIP|CONSTRAINT_IK_STRETCH|CONSTRAINT_IK_POS; +} + +static void kinematic_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bKinematicConstraint *data= con->data; + bConstraintTarget *ct; - switch (constraint->type) { - case CONSTRAINT_TYPE_NULL: - case CONSTRAINT_TYPE_KINEMATIC: /* removed */ - break; - case CONSTRAINT_TYPE_PYTHON: - { - bPythonConstraint *data; - - data = constraint->data; - BPY_pyconstraint_eval(data, ownermat, targetmat); - } - break; - case CONSTRAINT_TYPE_ACTION: - { - bActionConstraint *data; - float temp[4][4]; - - data = constraint->data; - Mat4CpyMat4(temp, ownermat); - - Mat4MulMat4(ownermat, targetmat, temp); - } - break; - case CONSTRAINT_TYPE_LOCLIKE: - { - bLocateLikeConstraint *data; - float offset[3] = {0.0f, 0.0f, 0.0f}; + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} - data = constraint->data; +static void kinematic_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bKinematicConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void kinematic_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + bKinematicConstraint *data= con->data; + + if (VALID_CONS_TARGET(ct)) + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + else if (ct) { + if (data->flag & CONSTRAINT_IK_AUTO) { + Object *ob= cob->ob; - if (data->flag & LOCLIKE_OFFSET) - VECCOPY(offset, ownermat[3]); - - if (data->flag & LOCLIKE_X) { - ownermat[3][0] = targetmat[3][0]; - - if(data->flag & LOCLIKE_X_INVERT) ownermat[3][0] *= -1; - ownermat[3][0] += offset[0]; + if (ob == NULL) { + Mat4One(ct->matrix); } - if (data->flag & LOCLIKE_Y) { - ownermat[3][1] = targetmat[3][1]; - - if(data->flag & LOCLIKE_Y_INVERT) ownermat[3][1] *= -1; - ownermat[3][1] += offset[1]; - } - if (data->flag & LOCLIKE_Z) { - ownermat[3][2] = targetmat[3][2]; - - if(data->flag & LOCLIKE_Z_INVERT) ownermat[3][2] *= -1; - ownermat[3][2] += offset[2]; - } - } - break; - case CONSTRAINT_TYPE_ROTLIKE: - { - bRotateLikeConstraint *data; - float loc[3]; - float eul[3], obeul[3]; - float size[3]; - - data = constraint->data; - - VECCOPY(loc, ownermat[3]); - Mat4ToSize(ownermat, size); - - Mat4ToEul(targetmat, eul); - Mat4ToEul(ownermat, obeul); - - if ((data->flag & ROTLIKE_X)==0) { - eul[0] = obeul[0]; - } - else if (data->flag & ROTLIKE_X_INVERT) { - eul[0] *= -1; - } - - if ((data->flag & ROTLIKE_Y)==0) { - eul[1] = obeul[1]; - } - else if (data->flag & ROTLIKE_Y_INVERT) { - eul[1] *= -1; - } - - if ((data->flag & ROTLIKE_Z)==0) { - eul[2] = obeul[2]; - } - else if (data->flag & ROTLIKE_Z_INVERT) { - eul[2] *= -1; - } - - compatible_eul(eul, obeul); - LocEulSizeToMat4(ownermat, loc, eul, size); - } - break; - case CONSTRAINT_TYPE_SIZELIKE: - { - bSizeLikeConstraint *data; - float obsize[3], size[3]; - - data = constraint->data; - - Mat4ToSize(targetmat, size); - Mat4ToSize(ownermat, obsize); - - if ((data->flag & SIZELIKE_X) && obsize[0] != 0) - VecMulf(ownermat[0], size[0] / obsize[0]); - if ((data->flag & SIZELIKE_Y) && obsize[1] != 0) - VecMulf(ownermat[1], size[1] / obsize[1]); - if ((data->flag & SIZELIKE_Z) && obsize[2] != 0) - VecMulf(ownermat[2], size[2] / obsize[2]); - } - break; - case CONSTRAINT_TYPE_MINMAX: - { - bMinMaxConstraint *data; - float obmat[4][4], imat[4][4], tarmat[4][4], tmat[4][4]; - float val1, val2; - int index; - - data = constraint->data; - - Mat4CpyMat4(obmat, ownermat); - Mat4CpyMat4(tarmat, targetmat); - - if (data->flag & MINMAX_USEROT) { - /* take rotation of target into account by doing the transaction in target's localspace */ - Mat4Invert(imat, tarmat); - Mat4MulMat4(tmat, obmat, imat); - Mat4CpyMat4(obmat, tmat); - Mat4One(tarmat); - } - - switch (data->minmaxflag) { - case TRACK_Z: - val1 = tarmat[3][2]; - val2 = obmat[3][2]-data->offset; - index = 2; - break; - case TRACK_Y: - val1 = tarmat[3][1]; - val2 = obmat[3][1]-data->offset; - index = 1; - break; - case TRACK_X: - val1 = tarmat[3][0]; - val2 = obmat[3][0]-data->offset; - index = 0; - break; - case TRACK_nZ: - val2 = tarmat[3][2]; - val1 = obmat[3][2]-data->offset; - index = 2; - break; - case TRACK_nY: - val2 = tarmat[3][1]; - val1 = obmat[3][1]-data->offset; - index = 1; - break; - case TRACK_nX: - val2 = tarmat[3][0]; - val1 = obmat[3][0]-data->offset; - index = 0; - break; - default: - return; - } - - if (val1 > val2) { - obmat[3][index] = tarmat[3][index] + data->offset; - if (data->flag & MINMAX_STICKY) { - if (data->flag & MINMAX_STUCK) { - VECCOPY(obmat[3], data->cache); - } - else { - VECCOPY(data->cache, obmat[3]); - data->flag |= MINMAX_STUCK; - } - } - if (data->flag & MINMAX_USEROT) { - /* get out of localspace */ - Mat4MulMat4(tmat, obmat, targetmat); - Mat4CpyMat4(ownermat, tmat); - } - else { - VECCOPY(ownermat[3], obmat[3]); - } - } else { - data->flag &= ~MINMAX_STUCK; + float vec[3]; + /* move grabtarget into world space */ + VECCOPY(vec, data->grabtarget); + Mat4MulVecfl(ob->obmat, vec); + Mat4CpyMat4(ct->matrix, ob->obmat); + VECCOPY(ct->matrix[3], vec); } } - break; - case CONSTRAINT_TYPE_TRACKTO: - { - bTrackToConstraint *data; - float size[3], vec[3]; - float totmat[3][3]; - float tmat[4][4]; + else + Mat4One(ct->matrix); + } +} - data = constraint->data; +static bConstraintTypeInfo CTI_KINEMATIC = { + CONSTRAINT_TYPE_KINEMATIC, /* type */ + sizeof(bKinematicConstraint), /* size */ + "IK", /* name */ + "bKinematicConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + kinematic_new_data, /* new data */ + kinematic_get_tars, /* get constraint targets */ + kinematic_flush_tars, /* flush constraint targets */ + kinematic_get_tarmat, /* get target matrix */ + NULL /* evaluate - solved as separate loop */ +}; + +/* -------- Follow-Path Constraint ---------- */ + +static void followpath_new_data (void *cdata) +{ + bFollowPathConstraint *data= (bFollowPathConstraint *)cdata; + + data->trackflag = TRACK_Y; + data->upflag = UP_Z; + data->offset = 0; + data->followflag = 0; +} + +static void followpath_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bFollowPathConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints without subtargets */ + SINGLETARGETNS_GET_TARS(con, data, ct, list) + } +} + +static void followpath_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bFollowPathConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGETNS_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + bFollowPathConstraint *data= con->data; + + if (VALID_CONS_TARGET(ct)) { + Curve *cu= ct->tar->data; + float q[4], vec[4], dir[3], *quat, x1; + float totmat[4][4]; + float curvetime; + + Mat4One(totmat); + Mat4One(ct->matrix); + + /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, + * currently for paths to work it needs to go through the bevlist/displist system (ton) + */ + + /* only happens on reload file, but violates depsgraph still... fix! */ + if (cu->path==NULL || cu->path->data==NULL) + makeDispListCurveTypes(ct->tar, 0); + + if (cu->path && cu->path->data) { + curvetime= bsystem_time(ct->tar, (float)ctime, 0.0) - data->offset; - if (data->tar) { - /* Get size property, since ob->size is only the object's own relative size, not its global one */ - Mat4ToSize(ownermat, size); - - /* Clear the object's rotation */ - ownermat[0][0]=size[0]; - ownermat[0][1]=0; - ownermat[0][2]=0; - ownermat[1][0]=0; - ownermat[1][1]=size[1]; - ownermat[1][2]=0; - ownermat[2][0]=0; - ownermat[2][1]=0; - ownermat[2][2]=size[2]; - - /* targetmat[2] instead of ownermat[2] is passed to vectomat - * for backwards compatability it seems... (Aligorith) - */ - VecSubf(vec, ownermat[3], targetmat[3]); - vectomat(vec, targetmat[2], - (short)data->reserved1, (short)data->reserved2, - data->flags, totmat); - - Mat4CpyMat4(tmat, ownermat); - Mat4MulMat34(ownermat, totmat, tmat); + if (calc_ipo_spec(cu->ipo, CU_SPEED, &curvetime)==0) { + curvetime /= cu->pathlen; + CLAMP(curvetime, 0.0, 1.0); } - } - break; - case CONSTRAINT_TYPE_LOCKTRACK: - { - bLockTrackConstraint *data; - float vec[3],vec2[3]; - float totmat[3][3]; - float tmpmat[3][3]; - float invmat[3][3]; - float tmat[4][4]; - float mdet; - - data = constraint->data; - if (data->tar) { - /* Vector object -> target */ - VecSubf(vec, targetmat[3], ownermat[3]); - switch (data->lockflag){ - case LOCK_X: /* LOCK X */ - { - switch (data->trackflag) { - case TRACK_Y: /* LOCK X TRACK Y */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[0]); - VecSubf(totmat[1], vec, vec2); - Normalize(totmat[1]); - - /* the x axis is fixed */ - totmat[0][0] = ownermat[0][0]; - totmat[0][1] = ownermat[0][1]; - totmat[0][2] = ownermat[0][2]; - Normalize(totmat[0]); - - /* the z axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[2], totmat[0], totmat[1]); - } - break; - case TRACK_Z: /* LOCK X TRACK Z */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[0]); - VecSubf(totmat[2], vec, vec2); - Normalize(totmat[2]); - - /* the x axis is fixed */ - totmat[0][0] = ownermat[0][0]; - totmat[0][1] = ownermat[0][1]; - totmat[0][2] = ownermat[0][2]; - Normalize(totmat[0]); + if ( where_on_path(ct->tar, curvetime, vec, dir) ) { + if (data->followflag) { + quat= vectoquat(dir, (short) data->trackflag, (short) data->upflag); - /* the z axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[1], totmat[2], totmat[0]); - } - break; - case TRACK_nY: /* LOCK X TRACK -Y */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[0]); - VecSubf(totmat[1], vec, vec2); - Normalize(totmat[1]); - VecMulf(totmat[1],-1); - - /* the x axis is fixed */ - totmat[0][0] = ownermat[0][0]; - totmat[0][1] = ownermat[0][1]; - totmat[0][2] = ownermat[0][2]; - Normalize(totmat[0]); - - /* the z axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[2], totmat[0], totmat[1]); - } - break; - case TRACK_nZ: /* LOCK X TRACK -Z */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[0]); - VecSubf(totmat[2], vec, vec2); - Normalize(totmat[2]); - VecMulf(totmat[2],-1); - - /* the x axis is fixed */ - totmat[0][0] = ownermat[0][0]; - totmat[0][1] = ownermat[0][1]; - totmat[0][2] = ownermat[0][2]; - Normalize(totmat[0]); - - /* the z axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[1], totmat[2], totmat[0]); - } - break; - default: - { - totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; - totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; - totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; - } - break; - } + Normalize(dir); + q[0]= (float)cos(0.5*vec[3]); + x1= (float)sin(0.5*vec[3]); + q[1]= -x1*dir[0]; + q[2]= -x1*dir[1]; + q[3]= -x1*dir[2]; + QuatMul(quat, q, quat); + + QuatToMat4(quat, totmat); } - break; - case LOCK_Y: /* LOCK Y */ - { - switch (data->trackflag) { - case TRACK_X: /* LOCK Y TRACK X */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[1]); - VecSubf(totmat[0], vec, vec2); - Normalize(totmat[0]); - - /* the y axis is fixed */ - totmat[1][0] = ownermat[1][0]; - totmat[1][1] = ownermat[1][1]; - totmat[1][2] = ownermat[1][2]; - Normalize(totmat[1]); - - /* the z axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[2], totmat[0], totmat[1]); - } - break; - case TRACK_Z: /* LOCK Y TRACK Z */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[1]); - VecSubf(totmat[2], vec, vec2); - Normalize(totmat[2]); + VECCOPY(totmat[3], vec); + + Mat4MulSerie(ct->matrix, ct->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL); + } + } + } + else if (ct) + Mat4One(ct->matrix); +} - /* the y axis is fixed */ - totmat[1][0] = ownermat[1][0]; - totmat[1][1] = ownermat[1][1]; - totmat[1][2] = ownermat[1][2]; - Normalize(totmat[1]); - - /* the z axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[0], totmat[1], totmat[2]); - } - break; - case TRACK_nX: /* LOCK Y TRACK -X */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[1]); - VecSubf(totmat[0], vec, vec2); - Normalize(totmat[0]); - VecMulf(totmat[0],-1); - - /* the y axis is fixed */ - totmat[1][0] = ownermat[1][0]; - totmat[1][1] = ownermat[1][1]; - totmat[1][2] = ownermat[1][2]; - Normalize(totmat[1]); - - /* the z axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[2], totmat[0], totmat[1]); - } - break; - case TRACK_nZ: /* LOCK Y TRACK -Z */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[1]); - VecSubf(totmat[2], vec, vec2); - Normalize(totmat[2]); - VecMulf(totmat[2],-1); - - /* the y axis is fixed */ - totmat[1][0] = ownermat[1][0]; - totmat[1][1] = ownermat[1][1]; - totmat[1][2] = ownermat[1][2]; - Normalize(totmat[1]); - - /* the z axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[0], totmat[1], totmat[2]); - } - break; - default: - { - totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; - totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; - totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; - } - break; - } +static void followpath_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float obmat[4][4]; + float size[3], obsize[3]; + + /* get Object local transform (loc/rot/size) to determine transformation from path */ + //object_to_mat4(ob, obmat); + Mat4CpyMat4(obmat, cob->matrix); // FIXME!!! + + /* get scaling of object before applying constraint */ + Mat4ToSize(cob->matrix, size); + + /* apply targetmat - containing location on path, and rotation */ + Mat4MulSerie(cob->matrix, ct->matrix, obmat, NULL, NULL, NULL, NULL, NULL, NULL); + + /* un-apply scaling caused by path */ + Mat4ToSize(cob->matrix, obsize); + if (obsize[0]) + VecMulf(cob->matrix[0], size[0] / obsize[0]); + if (obsize[1]) + VecMulf(cob->matrix[1], size[1] / obsize[1]); + if (obsize[2]) + VecMulf(cob->matrix[2], size[2] / obsize[2]); + } +} + +static bConstraintTypeInfo CTI_FOLLOWPATH = { + CONSTRAINT_TYPE_FOLLOWPATH, /* type */ + sizeof(bFollowPathConstraint), /* size */ + "Follow Path", /* name */ + "bFollowPathConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + followpath_new_data, /* new data */ + followpath_get_tars, /* get constraint targets */ + followpath_flush_tars, /* flush constraint targets */ + followpath_get_tarmat, /* get target matrix */ + followpath_evaluate /* evaluate */ +}; + +/* --------- Limit Location --------- */ + + +static void loclimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bLocLimitConstraint *data = con->data; + + if (data->flag & LIMIT_XMIN) { + if (cob->matrix[3][0] < data->xmin) + cob->matrix[3][0] = data->xmin; + } + if (data->flag & LIMIT_XMAX) { + if (cob->matrix[3][0] > data->xmax) + cob->matrix[3][0] = data->xmax; + } + if (data->flag & LIMIT_YMIN) { + if (cob->matrix[3][1] < data->ymin) + cob->matrix[3][1] = data->ymin; + } + if (data->flag & LIMIT_YMAX) { + if (cob->matrix[3][1] > data->ymax) + cob->matrix[3][1] = data->ymax; + } + if (data->flag & LIMIT_ZMIN) { + if (cob->matrix[3][2] < data->zmin) + cob->matrix[3][2] = data->zmin; + } + if (data->flag & LIMIT_ZMAX) { + if (cob->matrix[3][2] > data->zmax) + cob->matrix[3][2] = data->zmax; + } +} + +static bConstraintTypeInfo CTI_LOCLIMIT = { + CONSTRAINT_TYPE_LOCLIMIT, /* type */ + sizeof(bLocLimitConstraint), /* size */ + "Limit Location", /* name */ + "bLocLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + NULL, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + loclimit_evaluate /* evaluate */ +}; + +/* -------- Limit Rotation --------- */ + +static void rotlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bRotLimitConstraint *data = con->data; + float loc[3]; + float eul[3]; + float size[3]; + + VECCOPY(loc, cob->matrix[3]); + Mat4ToSize(cob->matrix, size); + + Mat4ToEul(cob->matrix, eul); + + /* eulers: radians to degrees! */ + eul[0] = (eul[0] / M_PI * 180); + eul[1] = (eul[1] / M_PI * 180); + eul[2] = (eul[2] / M_PI * 180); + + /* limiting of euler values... */ + if (data->flag & LIMIT_XROT) { + if (eul[0] < data->xmin) + eul[0] = data->xmin; + + if (eul[0] > data->xmax) + eul[0] = data->xmax; + } + if (data->flag & LIMIT_YROT) { + if (eul[1] < data->ymin) + eul[1] = data->ymin; + + if (eul[1] > data->ymax) + eul[1] = data->ymax; + } + if (data->flag & LIMIT_ZROT) { + if (eul[2] < data->zmin) + eul[2] = data->zmin; + + if (eul[2] > data->zmax) + eul[2] = data->zmax; + } + + /* eulers: degrees to radians ! */ + eul[0] = (eul[0] / 180 * M_PI); + eul[1] = (eul[1] / 180 * M_PI); + eul[2] = (eul[2] / 180 * M_PI); + + LocEulSizeToMat4(cob->matrix, loc, eul, size); +} + +static bConstraintTypeInfo CTI_ROTLIMIT = { + CONSTRAINT_TYPE_ROTLIMIT, /* type */ + sizeof(bRotLimitConstraint), /* size */ + "Limit Rotation", /* name */ + "bRotLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + NULL, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + rotlimit_evaluate /* evaluate */ +}; + +/* --------- Limit Scaling --------- */ + + +static void sizelimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bSizeLimitConstraint *data = con->data; + float obsize[3], size[3]; + + Mat4ToSize(cob->matrix, size); + Mat4ToSize(cob->matrix, obsize); + + if (data->flag & LIMIT_XMIN) { + if (size[0] < data->xmin) + size[0] = data->xmin; + } + if (data->flag & LIMIT_XMAX) { + if (size[0] > data->xmax) + size[0] = data->xmax; + } + if (data->flag & LIMIT_YMIN) { + if (size[1] < data->ymin) + size[1] = data->ymin; + } + if (data->flag & LIMIT_YMAX) { + if (size[1] > data->ymax) + size[1] = data->ymax; + } + if (data->flag & LIMIT_ZMIN) { + if (size[2] < data->zmin) + size[2] = data->zmin; + } + if (data->flag & LIMIT_ZMAX) { + if (size[2] > data->zmax) + size[2] = data->zmax; + } + + if (obsize[0]) + VecMulf(cob->matrix[0], size[0]/obsize[0]); + if (obsize[1]) + VecMulf(cob->matrix[1], size[1]/obsize[1]); + if (obsize[2]) + VecMulf(cob->matrix[2], size[2]/obsize[2]); +} + +static bConstraintTypeInfo CTI_SIZELIMIT = { + CONSTRAINT_TYPE_SIZELIMIT, /* type */ + sizeof(bSizeLimitConstraint), /* size */ + "Limit Scaling", /* name */ + "bSizeLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + NULL, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + sizelimit_evaluate /* evaluate */ +}; + +/* ----------- Copy Location ------------- */ + +static void loclike_new_data (void *cdata) +{ + bLocateLikeConstraint *data= (bLocateLikeConstraint *)cdata; + + data->flag = LOCLIKE_X|LOCLIKE_Y|LOCLIKE_Z; +} + +static void loclike_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bLocateLikeConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} + +static void loclike_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bLocateLikeConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void loclike_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + bLocateLikeConstraint *data = con->data; + + if (VALID_CONS_TARGET(ct)) { + if (ct->tar->type==OB_ARMATURE && strlen(ct->subtarget)) { + /* Pose-Channels for the CopyLoc target are handled specially, so that + * we can support using the bone-tip as an option. + */ + bPoseChannel *pchan; + float tmat[4][4]; + + pchan = get_pose_channel(ct->tar->pose, ct->subtarget); + if (pchan) { + Mat4CpyMat4(tmat, pchan->pose_mat); + + if (data->flag & LOCLIKE_TIP) { + VECCOPY(tmat[3], pchan->pose_tail); + } + + Mat4MulMat4(ct->matrix, tmat, ct->tar->obmat); + } + else + Mat4CpyMat4(ct->matrix, ct->tar->obmat); + + /* convert matrix space as required */ + constraint_mat_convertspace(ct->tar, pchan, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + } + else { + /* get target matrix as is done normally for other constraints */ + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + } + } + else if (ct) + Mat4One(ct->matrix); +} + +static void loclike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bLocateLikeConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float offset[3] = {0.0f, 0.0f, 0.0f}; + + if (data->flag & LOCLIKE_OFFSET) + VECCOPY(offset, cob->matrix[3]); + + if (data->flag & LOCLIKE_X) { + cob->matrix[3][0] = ct->matrix[3][0]; + + if (data->flag & LOCLIKE_X_INVERT) cob->matrix[3][0] *= -1; + cob->matrix[3][0] += offset[0]; + } + if (data->flag & LOCLIKE_Y) { + cob->matrix[3][1] = ct->matrix[3][1]; + + if (data->flag & LOCLIKE_Y_INVERT) cob->matrix[3][1] *= -1; + cob->matrix[3][1] += offset[1]; + } + if (data->flag & LOCLIKE_Z) { + cob->matrix[3][2] = ct->matrix[3][2]; + + if (data->flag & LOCLIKE_Z_INVERT) cob->matrix[3][2] *= -1; + cob->matrix[3][2] += offset[2]; + } + } +} + +static bConstraintTypeInfo CTI_LOCLIKE = { + CONSTRAINT_TYPE_LOCLIKE, /* type */ + sizeof(bLocateLikeConstraint), /* size */ + "Copy Location", /* name */ + "bLocateLikeConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + loclike_new_data, /* new data */ + loclike_get_tars, /* get constraint targets */ + loclike_flush_tars, /* flush constraint targets */ + loclike_get_tarmat, /* get target matrix */ + loclike_evaluate /* evaluate */ +}; + +/* ----------- Copy Rotation ------------- */ + +static void rotlike_new_data (void *cdata) +{ + bRotateLikeConstraint *data= (bRotateLikeConstraint *)cdata; + + data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z; +} + +static void rotlike_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bRotateLikeConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} + +static void rotlike_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bRotateLikeConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void rotlike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bRotateLikeConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float loc[3]; + float eul[3], obeul[3]; + float size[3]; + + VECCOPY(loc, cob->matrix[3]); + Mat4ToSize(cob->matrix, size); + + Mat4ToEul(ct->matrix, eul); + Mat4ToEul(cob->matrix, obeul); + + if ((data->flag & ROTLIKE_X)==0) { + eul[0] = obeul[0]; + } + else if (data->flag & ROTLIKE_X_INVERT) { + eul[0] *= -1; + } + + if ((data->flag & ROTLIKE_Y)==0) { + eul[1] = obeul[1]; + } + else if (data->flag & ROTLIKE_Y_INVERT) { + eul[1] *= -1; + } + + if ((data->flag & ROTLIKE_Z)==0) { + eul[2] = obeul[2]; + } + else if (data->flag & ROTLIKE_Z_INVERT) { + eul[2] *= -1; + } + + compatible_eul(eul, obeul); + LocEulSizeToMat4(cob->matrix, loc, eul, size); + } +} + +static bConstraintTypeInfo CTI_ROTLIKE = { + CONSTRAINT_TYPE_ROTLIKE, /* type */ + sizeof(bRotateLikeConstraint), /* size */ + "Copy Rotation", /* name */ + "bRotateLikeConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + rotlike_new_data, /* new data */ + rotlike_get_tars, /* get constraint targets */ + rotlike_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + rotlike_evaluate /* evaluate */ +}; + +/* ---------- Copy Scaling ---------- */ + +static void sizelike_new_data (void *cdata) +{ + bSizeLikeConstraint *data= (bSizeLikeConstraint *)cdata; + + data->flag = SIZELIKE_X|SIZELIKE_Y|SIZELIKE_Z; +} + +static void sizelike_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bSizeLikeConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} + +static void sizelike_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bSizeLikeConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void sizelike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bSizeLikeConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float obsize[3], size[3]; + + Mat4ToSize(ct->matrix, size); + Mat4ToSize(cob->matrix, obsize); + + if ((data->flag & SIZELIKE_X) && obsize[0] != 0) + VecMulf(cob->matrix[0], size[0] / obsize[0]); + if ((data->flag & SIZELIKE_Y) && obsize[1] != 0) + VecMulf(cob->matrix[1], size[1] / obsize[1]); + if ((data->flag & SIZELIKE_Z) && obsize[2] != 0) + VecMulf(cob->matrix[2], size[2] / obsize[2]); + } +} + +static bConstraintTypeInfo CTI_SIZELIKE = { + CONSTRAINT_TYPE_SIZELIKE, /* type */ + sizeof(bSizeLikeConstraint), /* size */ + "Copy Scale", /* name */ + "bSizeLikeConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + sizelike_new_data, /* new data */ + sizelike_get_tars, /* get constraint targets */ + sizelike_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + sizelike_evaluate /* evaluate */ +}; + +/* ----------- Python Constraint -------------- */ + +static void pycon_free (bConstraint *con) +{ + bPythonConstraint *data= con->data; + bConstraintTarget *ct; + + /* id-properties */ + IDP_FreeProperty(data->prop); + MEM_freeN(data->prop); + + /* multiple targets */ + while ( (ct = data->targets.first) ) + MEM_freeN(ct); +} + +static void pycon_relink (bConstraint *con) +{ + bPythonConstraint *data= con->data; + + ID_NEW(data->text); +} + +static void pycon_copy (bConstraint *con, bConstraint *srccon) +{ + bPythonConstraint *pycon = (bPythonConstraint *)con->data; + bPythonConstraint *opycon = (bPythonConstraint *)srccon->data; + + pycon->prop = IDP_CopyProperty(opycon->prop); + duplicatelist(&pycon->targets, &opycon->targets); +} + +static void pycon_new_data (void *cdata) +{ + bPythonConstraint *data= (bPythonConstraint *)cdata; + + /* everything should be set correctly by calloc, except for the prop->type constant.*/ + data->prop = MEM_callocN(sizeof(IDProperty), "PyConstraintProps"); + data->prop->type = IDP_GROUP; +} + +static void pycon_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bPythonConstraint *data= con->data; + + list->first = data->targets.first; + list->last = data->targets.last; + } +} + +/* Whether this approach is maintained remains to be seen (aligorith) */ +static void pycon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + bPythonConstraint *data= con->data; + + if (VALID_CONS_TARGET(ct)) { + /* special exception for curves - depsgraph issues */ + if (ct->tar->type == OB_CURVE) { + Curve *cu= ct->tar->data; + + /* this check is to make sure curve objects get updated on file load correctly.*/ + if (cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */ + makeDispListCurveTypes(ct->tar, 0); + } + + /* firstly calculate the matrix the normal way, then let the py-function override + * this matrix if it needs to do so + */ + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space); + BPY_pyconstraint_target(data, ct); + } + else if (ct) + Mat4One(ct->matrix); +} + +static void pycon_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bPythonConstraint *data= con->data; + +/* currently removed, until I this can be re-implemented for multiple targets */ +#if 0 + /* Firstly, run the 'driver' function which has direct access to the objects involved + * Technically, this is potentially dangerous as users may abuse this and cause dependency-problems, + * but it also allows certain 'clever' rigging hacks to work. + */ + BPY_pyconstraint_driver(data, cob, targets); +#endif + + /* Now, run the actual 'constraint' function, which should only access the matrices */ + BPY_pyconstraint_eval(data, cob, targets); +} + +static bConstraintTypeInfo CTI_PYTHON = { + CONSTRAINT_TYPE_PYTHON, /* type */ + sizeof(bPythonConstraint), /* size */ + "Script", /* name */ + "bPythonConstraint", /* struct name */ + pycon_free, /* free data */ + pycon_relink, /* relink data */ + pycon_copy, /* copy data */ + pycon_new_data, /* new data */ + pycon_get_tars, /* get constraint targets */ + NULL, /* flush constraint targets */ + pycon_get_tarmat, /* get target matrix */ + pycon_evaluate /* evaluate */ +}; + +/* -------- Action Constraint ----------- */ + +static void actcon_relink (bConstraint *con) +{ + bActionConstraint *data= con->data; + ID_NEW(data->act); +} + +static void actcon_new_data (void *cdata) +{ + bActionConstraint *data= (bActionConstraint *)cdata; + + /* set type to 20 (Loc X), as 0 is Rot X for backwards compatability */ + data->type = 20; +} + +static void actcon_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bActionConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} + +static void actcon_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bActionConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + extern void chan_calc_mat(bPoseChannel *chan); + bActionConstraint *data = con->data; + + if (VALID_CONS_TARGET(ct)) { + bPose *pose; + bPoseChannel *pchan, *tchan; + float tempmat[4][4], vec[3]; + float s, t; + short axis; + + /* initialise return matrix */ + Mat4One(ct->matrix); + + /* currently, only pose-channels are supported owners for action constraints, as + * the method for extracting the pose from the actions is currently hardcoded for + * poses... this may change in the future + */ + if (cob->type != CONSTRAINT_OBTYPE_BONE) + return; + + /* get the transform matrix of the target */ + constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space); + + /* determine where in transform range target is */ + /* data->type is mapped as follows for backwards compatability: + * 00,01,02 - rotation (it used to be like this) + * 10,11,12 - scaling + * 20,21,22 - location + */ + if (data->type < 10) { + /* extract rotation (is in whatever space target should be in) */ + Mat4ToEul(tempmat, vec); + vec[0] *= (float)(180.0/M_PI); + vec[1] *= (float)(180.0/M_PI); + vec[2] *= (float)(180.0/M_PI); + axis= data->type; + } + else if (data->type < 20) { + /* extract scaling (is in whatever space target should be in) */ + Mat4ToSize(tempmat, vec); + axis= data->type - 10; + } + else { + /* extract location */ + VECCOPY(vec, tempmat[3]); + axis= data->type - 20; + } + + /* Target defines the animation */ + s = (vec[axis]-data->min) / (data->max-data->min); + CLAMP(s, 0, 1); + t = ( s * (data->end-data->start)) + data->start; + + /* Get the appropriate information from the action */ + /* a temporary pose is made for this... + * TODO: extend this to objects too + */ + pose = MEM_callocN(sizeof(bPose), "pose"); + + pchan = cob->pchan; + tchan= verify_pose_channel(pose, pchan->name); + extract_pose_from_action(pose, data->act, t); + + chan_calc_mat(tchan); + + Mat4CpyMat4(ct->matrix, tchan->chan_mat); + + /* Clean up */ + free_pose_channels(pose); + MEM_freeN(pose); + } +} + +static void actcon_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float temp[4][4]; + + /* Nice and simple... we just need to multiply the matrices, as the get_target_matrix + * function has already taken care of everything else. + */ + Mat4CpyMat4(temp, cob->matrix); + Mat4MulMat4(cob->matrix, ct->matrix, temp); + } +} + +static bConstraintTypeInfo CTI_ACTION = { + CONSTRAINT_TYPE_ACTION, /* type */ + sizeof(bActionConstraint), /* size */ + "Action", /* name */ + "bActionConstraint", /* struct name */ + NULL, /* free data */ + actcon_relink, /* relink data */ + NULL, /* copy data */ + actcon_new_data, /* new data */ + actcon_get_tars, /* get constraint targets */ + actcon_flush_tars, /* flush constraint targets */ + actcon_get_tarmat, /* get target matrix */ + actcon_evaluate /* evaluate */ +}; + +/* --------- Locked Track ---------- */ + +static void locktrack_new_data (void *cdata) +{ + bLockTrackConstraint *data= (bLockTrackConstraint *)cdata; + + data->trackflag = TRACK_Y; + data->lockflag = LOCK_Z; +} + +static void locktrack_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bLockTrackConstraint *data= con->data; + bConstraintTarget *ct; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} + +static void locktrack_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bLockTrackConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void locktrack_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bLockTrackConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + if (VALID_CONS_TARGET(ct)) { + float vec[3],vec2[3]; + float totmat[3][3]; + float tmpmat[3][3]; + float invmat[3][3]; + float tmat[4][4]; + float mdet; + + /* Vector object -> target */ + VecSubf(vec, ct->matrix[3], cob->matrix[3]); + switch (data->lockflag){ + case LOCK_X: /* LOCK X */ + { + switch (data->trackflag) { + case TRACK_Y: /* LOCK X TRACK Y */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[0]); + VecSubf(totmat[1], vec, vec2); + Normalize(totmat[1]); + + /* the x axis is fixed */ + totmat[0][0] = cob->matrix[0][0]; + totmat[0][1] = cob->matrix[0][1]; + totmat[0][2] = cob->matrix[0][2]; + Normalize(totmat[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[2], totmat[0], totmat[1]); } break; - case LOCK_Z: /* LOCK Z */ + case TRACK_Z: /* LOCK X TRACK Z */ { - switch (data->trackflag) { - case TRACK_X: /* LOCK Z TRACK X */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[2]); - VecSubf(totmat[0], vec, vec2); - Normalize(totmat[0]); - - /* the z axis is fixed */ - totmat[2][0] = ownermat[2][0]; - totmat[2][1] = ownermat[2][1]; - totmat[2][2] = ownermat[2][2]; - Normalize(totmat[2]); - - /* the x axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[1], totmat[2], totmat[0]); - } - break; - case TRACK_Y: /* LOCK Z TRACK Y */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[2]); - VecSubf(totmat[1], vec, vec2); - Normalize(totmat[1]); - - /* the z axis is fixed */ - totmat[2][0] = ownermat[2][0]; - totmat[2][1] = ownermat[2][1]; - totmat[2][2] = ownermat[2][2]; - Normalize(totmat[2]); - - /* the x axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[0], totmat[1], totmat[2]); - } - break; - case TRACK_nX: /* LOCK Z TRACK -X */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[2]); - VecSubf(totmat[0], vec, vec2); - Normalize(totmat[0]); - VecMulf(totmat[0],-1); - - /* the z axis is fixed */ - totmat[2][0] = ownermat[2][0]; - totmat[2][1] = ownermat[2][1]; - totmat[2][2] = ownermat[2][2]; - Normalize(totmat[2]); - - /* the x axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[1], totmat[2], totmat[0]); - } - break; - case TRACK_nY: /* LOCK Z TRACK -Y */ - { - /* Projection of Vector on the plane */ - Projf(vec2, vec, ownermat[2]); - VecSubf(totmat[1], vec, vec2); - Normalize(totmat[1]); - VecMulf(totmat[1],-1); - - /* the z axis is fixed */ - totmat[2][0] = ownermat[2][0]; - totmat[2][1] = ownermat[2][1]; - totmat[2][2] = ownermat[2][2]; - Normalize(totmat[2]); - - /* the x axis gets mapped onto a third orthogonal vector */ - Crossf(totmat[0], totmat[1], totmat[2]); - } - break; - default: - { - totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; - totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; - totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; - } - break; - } + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[0]); + VecSubf(totmat[2], vec, vec2); + Normalize(totmat[2]); + + /* the x axis is fixed */ + totmat[0][0] = cob->matrix[0][0]; + totmat[0][1] = cob->matrix[0][1]; + totmat[0][2] = cob->matrix[0][2]; + Normalize(totmat[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[1], totmat[2], totmat[0]); + } + break; + case TRACK_nY: /* LOCK X TRACK -Y */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[0]); + VecSubf(totmat[1], vec, vec2); + Normalize(totmat[1]); + VecMulf(totmat[1],-1); + + /* the x axis is fixed */ + totmat[0][0] = cob->matrix[0][0]; + totmat[0][1] = cob->matrix[0][1]; + totmat[0][2] = cob->matrix[0][2]; + Normalize(totmat[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[2], totmat[0], totmat[1]); + } + break; + case TRACK_nZ: /* LOCK X TRACK -Z */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[0]); + VecSubf(totmat[2], vec, vec2); + Normalize(totmat[2]); + VecMulf(totmat[2],-1); + + /* the x axis is fixed */ + totmat[0][0] = cob->matrix[0][0]; + totmat[0][1] = cob->matrix[0][1]; + totmat[0][2] = cob->matrix[0][2]; + Normalize(totmat[0]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[1], totmat[2], totmat[0]); } break; default: - { - totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; - totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; - totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; - } - break; - } - /* Block to keep matrix heading */ - tmpmat[0][0] = ownermat[0][0];tmpmat[0][1] = ownermat[0][1];tmpmat[0][2] = ownermat[0][2]; - tmpmat[1][0] = ownermat[1][0];tmpmat[1][1] = ownermat[1][1];tmpmat[1][2] = ownermat[1][2]; - tmpmat[2][0] = ownermat[2][0];tmpmat[2][1] = ownermat[2][1];tmpmat[2][2] = ownermat[2][2]; - Normalize(tmpmat[0]); - Normalize(tmpmat[1]); - Normalize(tmpmat[2]); - Mat3Inv(invmat,tmpmat); - Mat3MulMat3(tmpmat, totmat, invmat); - totmat[0][0] = tmpmat[0][0];totmat[0][1] = tmpmat[0][1];totmat[0][2] = tmpmat[0][2]; - totmat[1][0] = tmpmat[1][0];totmat[1][1] = tmpmat[1][1];totmat[1][2] = tmpmat[1][2]; - totmat[2][0] = tmpmat[2][0];totmat[2][1] = tmpmat[2][1];totmat[2][2] = tmpmat[2][2]; - - Mat4CpyMat4(tmat, ownermat); - - mdet = Det3x3( totmat[0][0],totmat[0][1],totmat[0][2], - totmat[1][0],totmat[1][1],totmat[1][2], - totmat[2][0],totmat[2][1],totmat[2][2]); - if (mdet==0) { + { totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; } - - /* apply out transformaton to the object */ - Mat4MulMat34(ownermat, totmat, tmat); + break; } } - break; - case CONSTRAINT_TYPE_FOLLOWPATH: + break; + case LOCK_Y: /* LOCK Y */ { - bFollowPathConstraint *data; - float obmat[4][4]; - float size[3], obsize[3]; - - data = constraint->data; - - if (data->tar) { - /* get Object local transform (loc/rot/size) to determine transformation from path */ - //object_to_mat4(ob, obmat); - Mat4CpyMat4(obmat, ownermat); // FIXME!!! - - /* get scaling of object before applying constraint */ - Mat4ToSize(ownermat, size); - - /* apply targetmat - containing location on path, and rotation */ - Mat4MulSerie(ownermat, targetmat, obmat, NULL, NULL, NULL, NULL, NULL, NULL); - - /* un-apply scaling caused by path */ - Mat4ToSize(ownermat, obsize); - if (obsize[0] != 0) - VecMulf(ownermat[0], size[0] / obsize[0]); - if (obsize[1] != 0) - VecMulf(ownermat[1], size[1] / obsize[1]); - if (obsize[2] != 0) - VecMulf(ownermat[2], size[2] / obsize[2]); - } - } - break; - case CONSTRAINT_TYPE_STRETCHTO: - { - bStretchToConstraint *data; - float size[3],scale[3],vec[3],xx[3],zz[3],orth[3]; - float totmat[3][3]; - float tmat[4][4]; - float dist; - - data = constraint->data; - Mat4ToSize (ownermat, size); - - if (data->tar) { - /* store X orientation before destroying obmat */ - xx[0] = ownermat[0][0]; - xx[1] = ownermat[0][1]; - xx[2] = ownermat[0][2]; - Normalize(xx); - - /* store Z orientation before destroying obmat */ - zz[0] = ownermat[2][0]; - zz[1] = ownermat[2][1]; - zz[2] = ownermat[2][2]; - Normalize(zz); - - VecSubf(vec, ownermat[3], targetmat[3]); - vec[0] /= size[0]; - vec[1] /= size[1]; - vec[2] /= size[2]; + switch (data->trackflag) { + case TRACK_X: /* LOCK Y TRACK X */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[1]); + VecSubf(totmat[0], vec, vec2); + Normalize(totmat[0]); + + /* the y axis is fixed */ + totmat[1][0] = cob->matrix[1][0]; + totmat[1][1] = cob->matrix[1][1]; + totmat[1][2] = cob->matrix[1][2]; + Normalize(totmat[1]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[2], totmat[0], totmat[1]); + } + break; + case TRACK_Z: /* LOCK Y TRACK Z */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[1]); + VecSubf(totmat[2], vec, vec2); + Normalize(totmat[2]); - dist = Normalize(vec); - //dist = VecLenf( ob->obmat[3], targetmat[3]); - - if (data->orglength == 0) data->orglength = dist; - if (data->bulge == 0) data->bulge = 1.0; - - scale[1] = dist/data->orglength; - switch (data->volmode) { - /* volume preserving scaling */ - case VOLUME_XZ : - scale[0] = 1.0f - (float)sqrt(data->bulge) + (float)sqrt(data->bulge*(data->orglength/dist)); - scale[2] = scale[0]; - break; - case VOLUME_X: - scale[0] = 1.0f + data->bulge * (data->orglength /dist - 1); - scale[2] = 1.0; - break; - case VOLUME_Z: - scale[0] = 1.0; - scale[2] = 1.0f + data->bulge * (data->orglength /dist - 1); - break; - /* don't care for volume */ - case NO_VOLUME: - scale[0] = 1.0; - scale[2] = 1.0; - break; - default: /* should not happen, but in case*/ - return; - } /* switch (data->volmode) */ - - /* Clear the object's rotation and scale */ - ownermat[0][0]=size[0]*scale[0]; - ownermat[0][1]=0; - ownermat[0][2]=0; - ownermat[1][0]=0; - ownermat[1][1]=size[1]*scale[1]; - ownermat[1][2]=0; - ownermat[2][0]=0; - ownermat[2][1]=0; - ownermat[2][2]=size[2]*scale[2]; - - VecSubf(vec, ownermat[3], targetmat[3]); - Normalize(vec); - - /* new Y aligns object target connection*/ - totmat[1][0] = -vec[0]; - totmat[1][1] = -vec[1]; - totmat[1][2] = -vec[2]; - switch (data->plane) { - case PLANE_X: - /* build new Z vector */ - /* othogonal to "new Y" "old X! plane */ - Crossf(orth, vec, xx); - Normalize(orth); - - /* new Z*/ - totmat[2][0] = orth[0]; - totmat[2][1] = orth[1]; - totmat[2][2] = orth[2]; - - /* we decided to keep X plane*/ - Crossf(xx, orth, vec); - Normalize(xx); - totmat[0][0] = xx[0]; - totmat[0][1] = xx[1]; - totmat[0][2] = xx[2]; - break; - case PLANE_Z: - /* build new X vector */ - /* othogonal to "new Y" "old Z! plane */ - Crossf(orth, vec, zz); - Normalize(orth); - - /* new X */ - totmat[0][0] = -orth[0]; - totmat[0][1] = -orth[1]; - totmat[0][2] = -orth[2]; - - /* we decided to keep Z */ - Crossf(zz, orth, vec); - Normalize(zz); - totmat[2][0] = zz[0]; - totmat[2][1] = zz[1]; - totmat[2][2] = zz[2]; - break; - } /* switch (data->plane) */ - - Mat4CpyMat4(tmat, ownermat); - - Mat4MulMat34(ownermat, totmat, tmat); - } - } - break; - case CONSTRAINT_TYPE_LOCLIMIT: - { - bLocLimitConstraint *data; - - data = constraint->data; - - if (data->flag & LIMIT_XMIN) { - if(ownermat[3][0] < data->xmin) - ownermat[3][0] = data->xmin; - } - if (data->flag & LIMIT_XMAX) { - if (ownermat[3][0] > data->xmax) - ownermat[3][0] = data->xmax; - } - if (data->flag & LIMIT_YMIN) { - if(ownermat[3][1] < data->ymin) - ownermat[3][1] = data->ymin; - } - if (data->flag & LIMIT_YMAX) { - if (ownermat[3][1] > data->ymax) - ownermat[3][1] = data->ymax; - } - if (data->flag & LIMIT_ZMIN) { - if(ownermat[3][2] < data->zmin) - ownermat[3][2] = data->zmin; - } - if (data->flag & LIMIT_ZMAX) { - if (ownermat[3][2] > data->zmax) - ownermat[3][2] = data->zmax; - } - } - break; - case CONSTRAINT_TYPE_ROTLIMIT: - { - bRotLimitConstraint *data; - float loc[3]; - float eul[3]; - float size[3]; - - data = constraint->data; - - VECCOPY(loc, ownermat[3]); - Mat4ToSize(ownermat, size); - - Mat4ToEul(ownermat, eul); - - /* eulers: radians to degrees! */ - eul[0] = (eul[0] / M_PI * 180); - eul[1] = (eul[1] / M_PI * 180); - eul[2] = (eul[2] / M_PI * 180); - - /* limiting of euler values... */ - if (data->flag & LIMIT_XROT) { - if (eul[0] < data->xmin) - eul[0] = data->xmin; + /* the y axis is fixed */ + totmat[1][0] = cob->matrix[1][0]; + totmat[1][1] = cob->matrix[1][1]; + totmat[1][2] = cob->matrix[1][2]; + Normalize(totmat[1]); - if (eul[0] > data->xmax) - eul[0] = data->xmax; - } - if (data->flag & LIMIT_YROT) { - if (eul[1] < data->ymin) - eul[1] = data->ymin; - - if (eul[1] > data->ymax) - eul[1] = data->ymax; - } - if (data->flag & LIMIT_ZROT) { - if (eul[2] < data->zmin) - eul[2] = data->zmin; - - if (eul[2] > data->zmax) - eul[2] = data->zmax; - } - - /* eulers: degrees to radians ! */ - eul[0] = (eul[0] / 180 * M_PI); - eul[1] = (eul[1] / 180 * M_PI); - eul[2] = (eul[2] / 180 * M_PI); - - LocEulSizeToMat4(ownermat, loc, eul, size); - } - break; - case CONSTRAINT_TYPE_SIZELIMIT: - { - bSizeLimitConstraint *data; - float obsize[3], size[3]; - - data = constraint->data; - - Mat4ToSize(ownermat, size); - Mat4ToSize(ownermat, obsize); - - if (data->flag & LIMIT_XMIN) { - if (size[0] < data->xmin) - size[0] = data->xmin; - } - if (data->flag & LIMIT_XMAX) { - if (size[0] > data->xmax) - size[0] = data->xmax; - } - if (data->flag & LIMIT_YMIN) { - if (size[1] < data->ymin) - size[1] = data->ymin; - } - if (data->flag & LIMIT_YMAX) { - if (size[1] > data->ymax) - size[1] = data->ymax; - } - if (data->flag & LIMIT_ZMIN) { - if (size[2] < data->zmin) - size[2] = data->zmin; - } - if (data->flag & LIMIT_ZMAX) { - if (size[2] > data->zmax) - size[2] = data->zmax; - } - - VecMulf(ownermat[0], size[0]/obsize[0]); - VecMulf(ownermat[1], size[1]/obsize[1]); - VecMulf(ownermat[2], size[2]/obsize[2]); - } - break; - case CONSTRAINT_TYPE_RIGIDBODYJOINT: - { - /* Do nothing. The GameEngine will take care of this.*/ - } - break; - case CONSTRAINT_TYPE_CLAMPTO: - { - bClampToConstraint *data; - Curve *cu; - float obmat[4][4], targetMatrix[4][4], ownLoc[3]; - float curveMin[3], curveMax[3]; - - data = constraint->data; - - /* prevent crash if user deletes curve */ - if ((data->tar == NULL) || (data->tar->type != OB_CURVE) ) - return; - else - cu= data->tar->data; - - Mat4CpyMat4(obmat, ownermat); - Mat4One(targetMatrix); - VECCOPY(ownLoc, obmat[3]); - - INIT_MINMAX(curveMin, curveMax) - minmax_object(data->tar, curveMin, curveMax); - - /* get targetmatrix */ - if (cu->path && cu->path->data) { - float vec[4], dir[3], totmat[4][4]; - float curvetime; - short clamp_axis; - - /* find best position on curve */ - /* 1. determine which axis to sample on? */ - if (data->flag == CLAMPTO_AUTO) { - float size[3]; - VecSubf(size, curveMax, curveMin); - - /* find axis along which the bounding box has the greatest - * extent. Otherwise, default to the x-axis, as that is quite - * frequently used. - */ - if ((size[2]>size[0]) && (size[2]>size[1])) - clamp_axis= CLAMPTO_Z - 1; - else if ((size[1]>size[0]) && (size[1]>size[2])) - clamp_axis= CLAMPTO_Y - 1; - else - clamp_axis = CLAMPTO_X - 1; + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[0], totmat[1], totmat[2]); } - else - clamp_axis= data->flag - 1; + break; + case TRACK_nX: /* LOCK Y TRACK -X */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[1]); + VecSubf(totmat[0], vec, vec2); + Normalize(totmat[0]); + VecMulf(totmat[0],-1); - /* 2. determine position relative to curve on a 0-1 scale based on bounding box */ - if (data->flag2 & CLAMPTO_CYCLIC) { - /* cyclic, so offset within relative bounding box is used */ - float len= (curveMax[clamp_axis] - curveMin[clamp_axis]); - float offset; + /* the y axis is fixed */ + totmat[1][0] = cob->matrix[1][0]; + totmat[1][1] = cob->matrix[1][1]; + totmat[1][2] = cob->matrix[1][2]; + Normalize(totmat[1]); - /* find bounding-box range where target is located */ - if (ownLoc[clamp_axis] < curveMin[clamp_axis]) { - /* bounding-box range is before */ - offset= curveMin[clamp_axis]; + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[2], totmat[0], totmat[1]); + } + break; + case TRACK_nZ: /* LOCK Y TRACK -Z */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[1]); + VecSubf(totmat[2], vec, vec2); + Normalize(totmat[2]); + VecMulf(totmat[2],-1); + + /* the y axis is fixed */ + totmat[1][0] = cob->matrix[1][0]; + totmat[1][1] = cob->matrix[1][1]; + totmat[1][2] = cob->matrix[1][2]; + Normalize(totmat[1]); + + /* the z axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[0], totmat[1], totmat[2]); + } + break; + default: + { + totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; + totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; + totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; + } + break; + } + } + break; + case LOCK_Z: /* LOCK Z */ + { + switch (data->trackflag) { + case TRACK_X: /* LOCK Z TRACK X */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[2]); + VecSubf(totmat[0], vec, vec2); + Normalize(totmat[0]); + + /* the z axis is fixed */ + totmat[2][0] = cob->matrix[2][0]; + totmat[2][1] = cob->matrix[2][1]; + totmat[2][2] = cob->matrix[2][2]; + Normalize(totmat[2]); + + /* the x axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[1], totmat[2], totmat[0]); + } + break; + case TRACK_Y: /* LOCK Z TRACK Y */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[2]); + VecSubf(totmat[1], vec, vec2); + Normalize(totmat[1]); + + /* the z axis is fixed */ + totmat[2][0] = cob->matrix[2][0]; + totmat[2][1] = cob->matrix[2][1]; + totmat[2][2] = cob->matrix[2][2]; + Normalize(totmat[2]); - while (ownLoc[clamp_axis] < offset) - offset -= len; - - /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */ - curvetime = (ownLoc[clamp_axis] - offset) / (len); - } - else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) { - /* bounding-box range is after */ - offset= curveMax[clamp_axis]; - - while (ownLoc[clamp_axis] > offset) { - if ((offset + len) > ownLoc[clamp_axis]) - break; - else - offset += len; - } - - /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */ - curvetime = (ownLoc[clamp_axis] - offset) / (len); - } - else { - /* as the location falls within bounds, just calculate */ - curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len); - } + /* the x axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[0], totmat[1], totmat[2]); } - else { - /* no cyclic, so position is clamped to within the bounding box */ - if (ownLoc[clamp_axis] <= curveMin[clamp_axis]) - curvetime = 0.0; - else if (ownLoc[clamp_axis] >= curveMax[clamp_axis]) - curvetime = 1.0; - else - curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]); - } - - /* 3. position on curve */ - if(where_on_path(data->tar, curvetime, vec, dir) ) { - Mat4One(totmat); - VECCOPY(totmat[3], vec); + break; + case TRACK_nX: /* LOCK Z TRACK -X */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[2]); + VecSubf(totmat[0], vec, vec2); + Normalize(totmat[0]); + VecMulf(totmat[0],-1); - Mat4MulSerie(targetMatrix, data->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL); + /* the z axis is fixed */ + totmat[2][0] = cob->matrix[2][0]; + totmat[2][1] = cob->matrix[2][1]; + totmat[2][2] = cob->matrix[2][2]; + Normalize(totmat[2]); + + /* the x axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[1], totmat[2], totmat[0]); } - } - - /* obtain final object position */ - VECCOPY(ownermat[3], targetMatrix[3]); - } - break; - case CONSTRAINT_TYPE_CHILDOF: - { - bChildOfConstraint *data; - - data = constraint->data; - - /* only evaluate if there is a target */ - if (data->tar) { - float parmat[4][4], invmat[4][4], tempmat[4][4]; - float loc[3], eul[3], size[3]; - float loco[3], eulo[3], sizo[3]; - - /* get offset (parent-inverse) matrix */ - Mat4CpyMat4(invmat, data->invmat); - - /* extract components of both matrices */ - VECCOPY(loc, targetmat[3]); - Mat4ToEul(targetmat, eul); - Mat4ToSize(targetmat, size); - - VECCOPY(loco, invmat[3]); - Mat4ToEul(invmat, eulo); - Mat4ToSize(invmat, sizo); - - /* disable channels not enabled */ - if (!(data->flag & CHILDOF_LOCX)) loc[0]= loco[0]= 0.0f; - if (!(data->flag & CHILDOF_LOCY)) loc[1]= loco[1]= 0.0f; - if (!(data->flag & CHILDOF_LOCZ)) loc[2]= loco[2]= 0.0f; - if (!(data->flag & CHILDOF_ROTX)) eul[0]= eulo[0]= 0.0f; - if (!(data->flag & CHILDOF_ROTY)) eul[1]= eulo[1]= 0.0f; - if (!(data->flag & CHILDOF_ROTZ)) eul[2]= eulo[2]= 0.0f; - if (!(data->flag & CHILDOF_SIZEX)) size[0]= sizo[0]= 1.0f; - if (!(data->flag & CHILDOF_SIZEY)) size[1]= sizo[1]= 1.0f; - if (!(data->flag & CHILDOF_SIZEZ)) size[2]= sizo[2]= 1.0f; - - /* make new target mat and offset mat */ - LocEulSizeToMat4(targetmat, loc, eul, size); - LocEulSizeToMat4(invmat, loco, eulo, sizo); - - /* multiply target (parent matrix) by offset (parent inverse) to get - * the effect of the parent that will be exherted on the owner - */ - Mat4MulMat4(parmat, invmat, targetmat); - - /* now multiply the parent matrix by the owner matrix to get the - * the effect of this constraint (i.e. owner is 'parented' to parent) - */ - Mat4CpyMat4(tempmat, ownermat); - Mat4MulMat4(ownermat, tempmat, parmat); - } - } - break; - case CONSTRAINT_TYPE_TRANSFORM: - { - bTransformConstraint *data; - - data = constraint->data; - - /* only work if there is a target */ - if (data->tar) { - float loc[3], eul[3], size[3]; - float dvec[3], sval[3]; - short i; - - /* obtain target effect */ - switch (data->from) { - case 2: /* scale */ - Mat4ToSize(targetmat, dvec); - break; - case 1: /* rotation */ - Mat4ToEul(targetmat, dvec); - break; - default: /* location */ - VecCopyf(dvec, targetmat[3]); - break; - } - - /* extract components of owner's matrix */ - VECCOPY(loc, ownermat[3]); - Mat4ToEul(ownermat, eul); - Mat4ToSize(ownermat, size); - - /* determine where in range current transforms lie */ - if (data->expo) { - for (i=0; i<3; i++) { - if (data->from_max[i] - data->from_min[i]) - sval[i]= (dvec[i] - data->from_min[i]) / (data->from_max[i] - data->from_min[i]); - else - sval[i]= 0.0f; - } - } - else { - /* clamp transforms out of range */ - for (i=0; i<3; i++) { - CLAMP(dvec[i], data->from_min[i], data->from_max[i]); - if (data->from_max[i] - data->from_min[i]) - sval[i]= (dvec[i] - data->from_min[i]) / (data->from_max[i] - data->from_min[i]); - else - sval[i]= 0.0f; - } - } - - /* convert radian<->degree */ - if (data->from==1 && data->to==0) { - /* from radians to degrees */ - for (i=0; i<3; i++) - sval[i] = sval[i] / M_PI * 180; - } - else if (data->from==0 && data->to==1) { - /* from degrees to radians */ - for (i=0; i<3; i++) - sval[i] = sval[i] / 180 * M_PI; - } - - /* apply transforms */ - switch (data->to) { - case 2: /* scaling */ - for (i=0; i<3; i++) - size[i]= data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i])); - break; - case 1: /* rotation */ - for (i=0; i<3; i++) { - float tmin, tmax; - - /* convert destination min/max ranges from degrees to radians */ - tmin= data->to_min[i] / M_PI * 180; - tmax= data->to_max[i] / M_PI * 180; - - eul[i]= tmin + (sval[data->map[i]] * (tmax - tmin)); - } - break; - default: /* location */ - /* get new location */ - for (i=0; i<3; i++) - loc[i]= (data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i]))); + break; + case TRACK_nY: /* LOCK Z TRACK -Y */ + { + /* Projection of Vector on the plane */ + Projf(vec2, vec, cob->matrix[2]); + VecSubf(totmat[1], vec, vec2); + Normalize(totmat[1]); + VecMulf(totmat[1],-1); + + /* the z axis is fixed */ + totmat[2][0] = cob->matrix[2][0]; + totmat[2][1] = cob->matrix[2][1]; + totmat[2][2] = cob->matrix[2][2]; + Normalize(totmat[2]); - /* add original location back on (so that it can still be moved) */ - VecAddf(loc, ownermat[3], loc); - break; + /* the x axis gets mapped onto a third orthogonal vector */ + Crossf(totmat[0], totmat[1], totmat[2]); } - - /* apply to matrix */ - LocEulSizeToMat4(ownermat, loc, eul, size); + break; + default: + { + totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; + totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; + totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; + } + break; } } - break; - default: - printf("Error: Unknown constraint type\n"); - break; + break; + default: + { + totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; + totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; + totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; + } + break; + } + /* Block to keep matrix heading */ + tmpmat[0][0] = cob->matrix[0][0];tmpmat[0][1] = cob->matrix[0][1];tmpmat[0][2] = cob->matrix[0][2]; + tmpmat[1][0] = cob->matrix[1][0];tmpmat[1][1] = cob->matrix[1][1];tmpmat[1][2] = cob->matrix[1][2]; + tmpmat[2][0] = cob->matrix[2][0];tmpmat[2][1] = cob->matrix[2][1];tmpmat[2][2] = cob->matrix[2][2]; + Normalize(tmpmat[0]); + Normalize(tmpmat[1]); + Normalize(tmpmat[2]); + Mat3Inv(invmat, tmpmat); + Mat3MulMat3(tmpmat, totmat, invmat); + totmat[0][0] = tmpmat[0][0];totmat[0][1] = tmpmat[0][1];totmat[0][2] = tmpmat[0][2]; + totmat[1][0] = tmpmat[1][0];totmat[1][1] = tmpmat[1][1];totmat[1][2] = tmpmat[1][2]; + totmat[2][0] = tmpmat[2][0];totmat[2][1] = tmpmat[2][1];totmat[2][2] = tmpmat[2][2]; + + Mat4CpyMat4(tmat, cob->matrix); + + mdet = Det3x3( totmat[0][0],totmat[0][1],totmat[0][2], + totmat[1][0],totmat[1][1],totmat[1][2], + totmat[2][0],totmat[2][1],totmat[2][2]); + if (mdet==0) { + totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0; + totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0; + totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1; + } + + /* apply out transformaton to the object */ + Mat4MulMat34(cob->matrix, totmat, tmat); } } -/* this function is called whenever constraints need to be evaluated */ +static bConstraintTypeInfo CTI_LOCKTRACK = { + CONSTRAINT_TYPE_LOCKTRACK, /* type */ + sizeof(bLockTrackConstraint), /* size */ + "Locked Track", /* name */ + "bLockTrackConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + locktrack_new_data, /* new data */ + locktrack_get_tars, /* get constraint targets */ + locktrack_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + locktrack_evaluate /* evaluate */ +}; + +/* ---------- Stretch To ------------ */ + +static void stretchto_new_data (void *cdata) +{ + bStretchToConstraint *data= (bStretchToConstraint *)cdata; + + data->volmode = 0; + data->plane = 0; + data->orglength = 0.0; + data->bulge = 1.0; +} + +static void stretchto_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bStretchToConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} + +static void stretchto_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bStretchToConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void stretchto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bStretchToConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float size[3], scale[3], vec[3], xx[3], zz[3], orth[3]; + float totmat[3][3]; + float tmat[4][4]; + float dist; + + /* store scaling before destroying obmat */ + Mat4ToSize(cob->matrix, size); + + /* store X orientation before destroying obmat */ + xx[0] = cob->matrix[0][0]; + xx[1] = cob->matrix[0][1]; + xx[2] = cob->matrix[0][2]; + Normalize(xx); + + /* store Z orientation before destroying obmat */ + zz[0] = cob->matrix[2][0]; + zz[1] = cob->matrix[2][1]; + zz[2] = cob->matrix[2][2]; + Normalize(zz); + + VecSubf(vec, cob->matrix[3], ct->matrix[3]); + vec[0] /= size[0]; + vec[1] /= size[1]; + vec[2] /= size[2]; + + dist = Normalize(vec); + //dist = VecLenf( ob->obmat[3], targetmat[3]); + + /* data->orglength==0 occurs on first run, and after 'R' button is clicked */ + if (data->orglength == 0) + data->orglength = dist; + if (data->bulge == 0) + data->bulge = 1.0; + + scale[1] = dist/data->orglength; + switch (data->volmode) { + /* volume preserving scaling */ + case VOLUME_XZ : + scale[0] = 1.0f - (float)sqrt(data->bulge) + (float)sqrt(data->bulge*(data->orglength/dist)); + scale[2] = scale[0]; + break; + case VOLUME_X: + scale[0] = 1.0f + data->bulge * (data->orglength /dist - 1); + scale[2] = 1.0; + break; + case VOLUME_Z: + scale[0] = 1.0; + scale[2] = 1.0f + data->bulge * (data->orglength /dist - 1); + break; + /* don't care for volume */ + case NO_VOLUME: + scale[0] = 1.0; + scale[2] = 1.0; + break; + default: /* should not happen, but in case*/ + return; + } /* switch (data->volmode) */ + + /* Clear the object's rotation and scale */ + cob->matrix[0][0]=size[0]*scale[0]; + cob->matrix[0][1]=0; + cob->matrix[0][2]=0; + cob->matrix[1][0]=0; + cob->matrix[1][1]=size[1]*scale[1]; + cob->matrix[1][2]=0; + cob->matrix[2][0]=0; + cob->matrix[2][1]=0; + cob->matrix[2][2]=size[2]*scale[2]; + + VecSubf(vec, cob->matrix[3], ct->matrix[3]); + Normalize(vec); + + /* new Y aligns object target connection*/ + totmat[1][0] = -vec[0]; + totmat[1][1] = -vec[1]; + totmat[1][2] = -vec[2]; + switch (data->plane) { + case PLANE_X: + /* build new Z vector */ + /* othogonal to "new Y" "old X! plane */ + Crossf(orth, vec, xx); + Normalize(orth); + + /* new Z*/ + totmat[2][0] = orth[0]; + totmat[2][1] = orth[1]; + totmat[2][2] = orth[2]; + + /* we decided to keep X plane*/ + Crossf(xx, orth, vec); + Normalize(xx); + totmat[0][0] = xx[0]; + totmat[0][1] = xx[1]; + totmat[0][2] = xx[2]; + break; + case PLANE_Z: + /* build new X vector */ + /* othogonal to "new Y" "old Z! plane */ + Crossf(orth, vec, zz); + Normalize(orth); + + /* new X */ + totmat[0][0] = -orth[0]; + totmat[0][1] = -orth[1]; + totmat[0][2] = -orth[2]; + + /* we decided to keep Z */ + Crossf(zz, orth, vec); + Normalize(zz); + totmat[2][0] = zz[0]; + totmat[2][1] = zz[1]; + totmat[2][2] = zz[2]; + break; + } /* switch (data->plane) */ + + Mat4CpyMat4(tmat, cob->matrix); + Mat4MulMat34(cob->matrix, totmat, tmat); + } +} + +static bConstraintTypeInfo CTI_STRETCHTO = { + CONSTRAINT_TYPE_STRETCHTO, /* type */ + sizeof(bStretchToConstraint), /* size */ + "Stretch To", /* name */ + "bStretchToConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + stretchto_new_data, /* new data */ + stretchto_get_tars, /* get constraint targets */ + stretchto_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + stretchto_evaluate /* evaluate */ +}; + +/* ---------- Floor ------------ */ + +static void minmax_new_data (void *cdata) +{ + bMinMaxConstraint *data= (bMinMaxConstraint *)cdata; + + data->minmaxflag = TRACK_Z; + data->offset = 0.0f; + data->cache[0] = data->cache[1] = data->cache[2] = 0.0f; + data->flag = 0; +} + +static void minmax_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bMinMaxConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} + +static void minmax_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bMinMaxConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void minmax_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bMinMaxConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float obmat[4][4], imat[4][4], tarmat[4][4], tmat[4][4]; + float val1, val2; + int index; + + Mat4CpyMat4(obmat, cob->matrix); + Mat4CpyMat4(tarmat, ct->matrix); + + if (data->flag & MINMAX_USEROT) { + /* take rotation of target into account by doing the transaction in target's localspace */ + Mat4Invert(imat, tarmat); + Mat4MulMat4(tmat, obmat, imat); + Mat4CpyMat4(obmat, tmat); + Mat4One(tarmat); + } + + switch (data->minmaxflag) { + case TRACK_Z: + val1 = tarmat[3][2]; + val2 = obmat[3][2]-data->offset; + index = 2; + break; + case TRACK_Y: + val1 = tarmat[3][1]; + val2 = obmat[3][1]-data->offset; + index = 1; + break; + case TRACK_X: + val1 = tarmat[3][0]; + val2 = obmat[3][0]-data->offset; + index = 0; + break; + case TRACK_nZ: + val2 = tarmat[3][2]; + val1 = obmat[3][2]-data->offset; + index = 2; + break; + case TRACK_nY: + val2 = tarmat[3][1]; + val1 = obmat[3][1]-data->offset; + index = 1; + break; + case TRACK_nX: + val2 = tarmat[3][0]; + val1 = obmat[3][0]-data->offset; + index = 0; + break; + default: + return; + } + + if (val1 > val2) { + obmat[3][index] = tarmat[3][index] + data->offset; + if (data->flag & MINMAX_STICKY) { + if (data->flag & MINMAX_STUCK) { + VECCOPY(obmat[3], data->cache); + } + else { + VECCOPY(data->cache, obmat[3]); + data->flag |= MINMAX_STUCK; + } + } + if (data->flag & MINMAX_USEROT) { + /* get out of localspace */ + Mat4MulMat4(tmat, obmat, ct->matrix); + Mat4CpyMat4(cob->matrix, tmat); + } + else { + VECCOPY(cob->matrix[3], obmat[3]); + } + } + else { + data->flag &= ~MINMAX_STUCK; + } + } +} + +static bConstraintTypeInfo CTI_MINMAX = { + CONSTRAINT_TYPE_MINMAX, /* type */ + sizeof(bMinMaxConstraint), /* size */ + "Floor", /* name */ + "bMinMaxConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + minmax_new_data, /* new data */ + minmax_get_tars, /* get constraint targets */ + minmax_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + minmax_evaluate /* evaluate */ +}; + +/* ------- RigidBody Joint ---------- */ + +static void rbj_new_data (void *cdata) +{ + bRigidBodyJointConstraint *data= (bRigidBodyJointConstraint *)cdata; + + // removed code which set target of this constraint + data->type=1; +} + +static void rbj_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bRigidBodyJointConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints without subtargets */ + SINGLETARGETNS_GET_TARS(con, data, ct, list) + } +} + +static void rbj_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bRigidBodyJointConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGETNS_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static bConstraintTypeInfo CTI_RIGIDBODYJOINT = { + CONSTRAINT_TYPE_RIGIDBODYJOINT, /* type */ + sizeof(bRigidBodyJointConstraint), /* size */ + "RigidBody Joint", /* name */ + "bRigidBodyJointConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + rbj_new_data, /* new data */ + rbj_get_tars, /* get constraint targets */ + rbj_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get target matrix */ + NULL /* evaluate - this is not solved here... is just an interface for game-engine */ +}; + +/* -------- Clamp To ---------- */ + +static void clampto_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bClampToConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints without subtargets */ + SINGLETARGETNS_GET_TARS(con, data, ct, list) + } +} + +static void clampto_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bClampToConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGETNS_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void clampto_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + if (VALID_CONS_TARGET(ct)) { + Curve *cu= ct->tar->data; + + /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, + * currently for paths to work it needs to go through the bevlist/displist system (ton) + */ + + /* only happens on reload file, but violates depsgraph still... fix! */ + if (cu->path==NULL || cu->path->data==NULL) + makeDispListCurveTypes(ct->tar, 0); + } + + /* technically, this isn't really needed for evaluation, but we don't know what else + * might end up calling this... + */ + if (ct) + Mat4One(ct->matrix); +} + +static void clampto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bClampToConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target and it is a curve */ + if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) { + Curve *cu= data->tar->data; + float obmat[4][4], targetMatrix[4][4], ownLoc[3]; + float curveMin[3], curveMax[3]; + + Mat4CpyMat4(obmat, cob->matrix); + Mat4One(targetMatrix); + VECCOPY(ownLoc, obmat[3]); + + INIT_MINMAX(curveMin, curveMax) + minmax_object(ct->tar, curveMin, curveMax); + + /* get targetmatrix */ + if (cu->path && cu->path->data) { + float vec[4], dir[3], totmat[4][4]; + float curvetime; + short clamp_axis; + + /* find best position on curve */ + /* 1. determine which axis to sample on? */ + if (data->flag == CLAMPTO_AUTO) { + float size[3]; + VecSubf(size, curveMax, curveMin); + + /* find axis along which the bounding box has the greatest + * extent. Otherwise, default to the x-axis, as that is quite + * frequently used. + */ + if ((size[2]>size[0]) && (size[2]>size[1])) + clamp_axis= CLAMPTO_Z - 1; + else if ((size[1]>size[0]) && (size[1]>size[2])) + clamp_axis= CLAMPTO_Y - 1; + else + clamp_axis = CLAMPTO_X - 1; + } + else + clamp_axis= data->flag - 1; + + /* 2. determine position relative to curve on a 0-1 scale based on bounding box */ + if (data->flag2 & CLAMPTO_CYCLIC) { + /* cyclic, so offset within relative bounding box is used */ + float len= (curveMax[clamp_axis] - curveMin[clamp_axis]); + float offset; + + /* find bounding-box range where target is located */ + if (ownLoc[clamp_axis] < curveMin[clamp_axis]) { + /* bounding-box range is before */ + offset= curveMin[clamp_axis]; + + while (ownLoc[clamp_axis] < offset) + offset -= len; + + /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */ + curvetime = (ownLoc[clamp_axis] - offset) / (len); + } + else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) { + /* bounding-box range is after */ + offset= curveMax[clamp_axis]; + + while (ownLoc[clamp_axis] > offset) { + if ((offset + len) > ownLoc[clamp_axis]) + break; + else + offset += len; + } + + /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */ + curvetime = (ownLoc[clamp_axis] - offset) / (len); + } + else { + /* as the location falls within bounds, just calculate */ + curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len); + } + } + else { + /* no cyclic, so position is clamped to within the bounding box */ + if (ownLoc[clamp_axis] <= curveMin[clamp_axis]) + curvetime = 0.0; + else if (ownLoc[clamp_axis] >= curveMax[clamp_axis]) + curvetime = 1.0; + else + curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]); + } + + /* 3. position on curve */ + if (where_on_path(ct->tar, curvetime, vec, dir) ) { + Mat4One(totmat); + VECCOPY(totmat[3], vec); + + Mat4MulSerie(targetMatrix, ct->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL); + } + } + + /* obtain final object position */ + VECCOPY(cob->matrix[3], targetMatrix[3]); + } +} + +static bConstraintTypeInfo CTI_CLAMPTO = { + CONSTRAINT_TYPE_CLAMPTO, /* type */ + sizeof(bClampToConstraint), /* size */ + "Clamp To", /* name */ + "bClampToConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + NULL, /* new data */ + clampto_get_tars, /* get constraint targets */ + clampto_flush_tars, /* flush constraint targets */ + clampto_get_tarmat, /* get target matrix */ + clampto_evaluate /* evaluate */ +}; + +/* ---------- Transform Constraint ----------- */ + +static void transform_new_data (void *cdata) +{ + bTransformConstraint *data= (bTransformConstraint *)cdata; + + data->map[0]= 0; + data->map[1]= 1; + data->map[2]= 2; +} + +static void transform_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bTransformConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data, ct, list) + } +} + +static void transform_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bTransformConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) + } +} + +static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bTransformConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float loc[3], eul[3], size[3]; + float dvec[3], sval[3]; + short i; + + /* obtain target effect */ + switch (data->from) { + case 2: /* scale */ + Mat4ToSize(ct->matrix, dvec); + break; + case 1: /* rotation */ + Mat4ToEul(ct->matrix, dvec); + break; + default: /* location */ + VecCopyf(dvec, ct->matrix[3]); + break; + } + + /* extract components of owner's matrix */ + VECCOPY(loc, cob->matrix[3]); + Mat4ToEul(cob->matrix, eul); + Mat4ToSize(cob->matrix, size); + + /* determine where in range current transforms lie */ + if (data->expo) { + for (i=0; i<3; i++) { + if (data->from_max[i] - data->from_min[i]) + sval[i]= (dvec[i] - data->from_min[i]) / (data->from_max[i] - data->from_min[i]); + else + sval[i]= 0.0f; + } + } + else { + /* clamp transforms out of range */ + for (i=0; i<3; i++) { + CLAMP(dvec[i], data->from_min[i], data->from_max[i]); + if (data->from_max[i] - data->from_min[i]) + sval[i]= (dvec[i] - data->from_min[i]) / (data->from_max[i] - data->from_min[i]); + else + sval[i]= 0.0f; + } + } + + /* convert radian<->degree */ + if (data->from==1 && data->to==0) { + /* from radians to degrees */ + for (i=0; i<3; i++) + sval[i] = sval[i] / M_PI * 180; + } + else if (data->from==0 && data->to==1) { + /* from degrees to radians */ + for (i=0; i<3; i++) + sval[i] = sval[i] / 180 * M_PI; + } + + /* apply transforms */ + switch (data->to) { + case 2: /* scaling */ + for (i=0; i<3; i++) + size[i]= data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i])); + break; + case 1: /* rotation */ + for (i=0; i<3; i++) { + float tmin, tmax; + + /* convert destination min/max ranges from degrees to radians */ + tmin= data->to_min[i] / M_PI * 180; + tmax= data->to_max[i] / M_PI * 180; + + eul[i]= tmin + (sval[data->map[i]] * (tmax - tmin)); + } + break; + default: /* location */ + /* get new location */ + for (i=0; i<3; i++) + loc[i]= (data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i]))); + + /* add original location back on (so that it can still be moved) */ + VecAddf(loc, cob->matrix[3], loc); + break; + } + + /* apply to matrix */ + LocEulSizeToMat4(cob->matrix, loc, eul, size); + } +} + +static bConstraintTypeInfo CTI_TRANSFORM = { + CONSTRAINT_TYPE_TRANSFORM, /* type */ + sizeof(bTransformConstraint), /* size */ + "Transform", /* name */ + "bTransformConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + transform_new_data, /* new data */ + transform_get_tars, /* get constraint targets */ + transform_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get a target matrix */ + transform_evaluate /* evaluate */ +}; + +/* ************************* Constraints Type-Info *************************** */ +/* All of the constraints api functions use bConstraintTypeInfo structs to carry out + * and operations that involve constraint specifc code. + */ + +/* These globals only ever get directly accessed in this file */ +static bConstraintTypeInfo *constraintsTypeInfo[NUM_CONSTRAINT_TYPES]; +static short CTI_INIT= 1; /* when non-zero, the list needs to be updated */ + +/* This function only gets called when CTI_INIT is non-zero */ +static void constraints_init_typeinfo () { + constraintsTypeInfo[0]= NULL; /* 'Null' Constraint */ + constraintsTypeInfo[1]= &CTI_CHILDOF; /* ChildOf Constraint */ + constraintsTypeInfo[2]= &CTI_TRACKTO; /* TrackTo Constraint */ + constraintsTypeInfo[3]= &CTI_KINEMATIC; /* IK Constraint */ + constraintsTypeInfo[4]= &CTI_FOLLOWPATH; /* Follow-Path Constraint */ + constraintsTypeInfo[5]= &CTI_ROTLIMIT; /* Limit Rotation Constraint */ + constraintsTypeInfo[6]= &CTI_LOCLIMIT; /* Limit Location Constraint */ + constraintsTypeInfo[7]= &CTI_SIZELIMIT; /* Limit Scaling Constraint */ + constraintsTypeInfo[8]= &CTI_ROTLIKE; /* Copy Rotation Constraint */ + constraintsTypeInfo[9]= &CTI_LOCLIKE; /* Copy Location Constraint */ + constraintsTypeInfo[10]= &CTI_SIZELIKE; /* Copy Scaling Constraint */ + constraintsTypeInfo[11]= &CTI_PYTHON; /* Python/Script Constraint */ + constraintsTypeInfo[12]= &CTI_ACTION; /* Action Constraint */ + constraintsTypeInfo[13]= &CTI_LOCKTRACK; /* Locked-Track Constraint */ + constraintsTypeInfo[14]= NULL; /* 'Distance Limit' Constraint */ + constraintsTypeInfo[15]= &CTI_STRETCHTO; /* StretchTo Constaint */ + constraintsTypeInfo[16]= &CTI_MINMAX; /* Floor Constraint */ + constraintsTypeInfo[17]= &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */ + constraintsTypeInfo[18]= &CTI_CLAMPTO; /* ClampTo Constraint */ + constraintsTypeInfo[19]= &CTI_TRANSFORM; /* Transformation Constraint */ +} + +/* This function should be used for getting the appropriate type-info when only + * a constraint type is known + */ +bConstraintTypeInfo *get_constraint_typeinfo (int type) +{ + /* initialise the type-info list? */ + if (CTI_INIT) { + constraints_init_typeinfo(); + CTI_INIT = 0; + } + + /* only return for valid types */ + if ( (type >= CONSTRAINT_TYPE_NULL) && + (type <= NUM_CONSTRAINT_TYPES ) ) + { + /* there shouldn't be any segfaults here... */ + return constraintsTypeInfo[type]; + } + else { + printf("No valid constraint type-info data available. Type = %i \n", type); + } + + return NULL; +} + +/* This function should always be used to get the appropriate type-info, as it + * has checks which prevent segfaults in some weird cases. + */ +bConstraintTypeInfo *constraint_get_typeinfo (bConstraint *con) +{ + /* only return typeinfo for valid constraints */ + if (con) + return get_constraint_typeinfo(con->type); + else + return NULL; +} + +/* ************************* General Constraints API ************************** */ +/* The functions here are called by various parts of Blender. Very few (should be none if possible) + * constraint-specific code should occur here. + */ + +/* ---------- Data Management ------- */ + +/* Free data of a specific constraint if it has any info */ +void free_constraint_data (bConstraint *con) +{ + if (con->data) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + + /* perform any special freeing constraint may have */ + if (cti && cti->free_data) + cti->free_data(con); + + /* free constraint data now */ + MEM_freeN(con->data); + } +} + +/* Free all constraints from a constraint-stack */ +void free_constraints (ListBase *conlist) +{ + bConstraint *con; + + /* Free constraint data and also any extra data */ + for (con= conlist->first; con; con= con->next) { + free_constraint_data(con); + } + + /* Free the whole list */ + BLI_freelistN(conlist); +} + +/* Reassign links that constraints have to other data (called during file loading?) */ +void relink_constraints (ListBase *conlist) +{ + bConstraint *con; + bConstraintTarget *ct; + + for (con= conlist->first; con; con= con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + + if (cti) { + /* relink any targets */ + if (cti->get_constraint_targets) { + ListBase targets = {NULL, NULL}; + + cti->get_constraint_targets(con, &targets); + for (ct= targets.first; ct; ct= ct->next) { + ID_NEW(ct->tar); + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + + /* relink any other special data */ + if (cti->relink_data) + cti->relink_data(con); + } + } +} + +/* duplicate all of the constraints in a constraint stack */ +void copy_constraints (ListBase *dst, ListBase *src) +{ + bConstraint *con, *srccon; + + dst->first= dst->last= NULL; + duplicatelist(dst, src); + + for (con=dst->first, srccon=src->first; con; srccon=srccon->next, con=con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + + /* make a new copy of the constraint's data */ + con->data = MEM_dupallocN(con->data); + + /* only do specific constraints if required */ + if (cti && cti->copy_data) + cti->copy_data(con, srccon); + } +} + +/* -------- Target-Matrix Stuff ------- */ + +/* This function is a relic from the prior implementations of the constraints system, when all + * constraints either had one or no targets. It used to be called during the main constraint solving + * loop, but is now only used for the remaining cases for a few constraints. + * + * None of the actual calculations of the matricies should be done here! Also, this function is + * not to be used by any new constraints, particularly any that have multiple targets. + */ +void get_constraint_target_matrix (bConstraint *con, short ownertype, void *ownerdata, float mat[][4], float ctime) +{ + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintOb *cob; + bConstraintTarget *ct; + + if (cti && cti->get_constraint_targets) { + /* make 'constraint-ob' */ + cob= MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb"); + cob->type= ownertype; + switch (ownertype) { + case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */ + { + cob->ob= (Object *)ownerdata; + cob->pchan= NULL; + if (cob->ob) { + Mat4CpyMat4(cob->matrix, cob->ob->obmat); + Mat4CpyMat4(cob->startmat, cob->matrix); + } + else { + Mat4One(cob->matrix); + Mat4One(cob->startmat); + } + } + break; + case CONSTRAINT_OBTYPE_BONE: /* this may occur in some cases */ + { + cob->ob= NULL; /* this might not work at all :/ */ + cob->pchan= (bPoseChannel *)ownerdata; + if (cob->pchan) { + Mat4CpyMat4(cob->matrix, cob->pchan->pose_mat); + Mat4CpyMat4(cob->startmat, cob->matrix); + } + else { + Mat4One(cob->matrix); + Mat4One(cob->startmat); + } + } + break; + } + + /* get targets - we only need the first one though (and there should only be one) */ + cti->get_constraint_targets(con, &targets); + + /* only calculate the target matrix on the first target */ + ct= (bConstraintTarget *)targets.first; + if (ct) { + if (cti->get_target_matrix) + cti->get_target_matrix(con, cob, ct, ctime); + Mat4CpyMat4(mat, ct->matrix); + } + + /* free targets + 'constraint-ob' */ + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 1); + MEM_freeN(cob); + } + else { + /* invalid constraint - perhaps... */ + Mat4One(mat); + } +} + +/* ---------- Evaluation ----------- */ + +/* This function is called whenever constraints need to be evaluated. Currently, all + * constraints that can be evaluated are everytime this gets run. + * + * constraints_make_evalob and constraints_clear_evalob should be called before and + * after running this function, to sort out cob + */ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime) { bConstraint *con; - void *ownerdata; - float tarmat[4][4], oldmat[4][4]; - float solution[4][4], delta[4][4], imat[4][4]; + float solution[4][4], delta[4][4]; + float oldmat[4][4], imat[4][4]; float enf; /* check that there is a valid constraint object to evaluate */ @@ -2848,43 +3309,59 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime) /* loop over available constraints, solving and blending them */ for (con= conlist->first; con; con= con->next) { - /* this we can skip completely */ + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + + /* these we can skip completely (invalid constraints...) */ + if (cti == NULL) continue; if (con->flag & CONSTRAINT_DISABLE) continue; + /* these constraints can't be evaluated anyway */ + if (cti->evaluate_constraint == NULL) continue; /* influence == 0 should be ignored */ if (con->enforce == 0.0f) continue; - /* and inverse kinematics is solved seperate */ - if (con->type==CONSTRAINT_TYPE_KINEMATIC) continue; - /* rigidbody is really a game-engine thing - and is not solved here */ - if (con->type==CONSTRAINT_TYPE_RIGIDBODYJOINT) continue; - /* influence of constraint */ - /* value should have been set from IPO's/Constraint Channels already */ + /* influence of constraint + * - value should have been set from IPO's/Constraint Channels already + */ enf = con->enforce; /* move owner matrix into right space */ constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); Mat4CpyMat4(oldmat, cob->matrix); - /* get the target matrix - in right space to be used */ - ownerdata= ((cob->pchan)? (void *)cob->pchan : (void *)cob->ob); - get_constraint_target_matrix(con, cob->type, ownerdata, tarmat, ctime); - - - /* Special Hack for PyConstraints to be able to set settings on the owner and/or - * target. Technically, this violates the design of constraints (as constraints should - * only act on matrices to alter the final transform of an owner), but on the other - * hand, this makes PyConstraints more powerful as it enables certain setups to be created - * and work reliably. - */ - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *pycon= (bPythonConstraint *)con->data; + /* prepare targets for constraint solving */ + if (cti->get_constraint_targets) { + bConstraintTarget *ct; - /* as usual, the function for this is defined in BPY_interface.c */ - BPY_pyconstraint_driver(pycon, cob, pycon->tar, pycon->subtarget); + /* get targets + * - constraints should use ct->matrix, not directly accessing values + * - ct->matrix members have not yet been calculated here! + */ + cti->get_constraint_targets(con, &targets); + + /* set matrices + * - calculate if possible, otherwise just initialise as identity matrix + */ + if (cti->get_target_matrix) { + for (ct= targets.first; ct; ct= ct->next) + cti->get_target_matrix(con, cob, ct, ctime); + } + else { + for (ct= targets.first; ct; ct= ct->next) + Mat4One(ct->matrix); + } } /* Solve the constraint */ - evaluate_constraint(con, cob->matrix, tarmat); + cti->evaluate_constraint(con, cob, &targets); + + /* clear targets after use + * - this should free temp targets but no data should be copied back + * as constraints may have done some nasty things to it... + */ + if (cti->flush_constraint_targets) { + cti->flush_constraint_targets(con, &targets, 1); + } /* Interpolate the enforcement, to blend result of constraint into final owner transform */ /* 1. Remove effects of original matrix from constraint solution ==> delta */ @@ -2904,7 +3381,7 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime) /* 3. Now multiply the delta by the matrix in use before the evaluation */ Mat4MulMat4(cob->matrix, delta, oldmat); - /* move target/owner back into worldspace for next constraint/other business */ + /* move owner back into worldspace for next constraint/other business */ if ((con->flag & CONSTRAINT_SPACEONCE) == 0) constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD); } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index eb651a925e0..fc7e6d61f8a 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -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 ) { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 20d61456f05..9f4c8f1607b 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -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); } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d07f05ddab1..7b0cdedddf2 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 4f09f51bc87..a059bf2a2c5 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -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); } } diff --git a/source/blender/include/BIF_editconstraint.h b/source/blender/include/BIF_editconstraint.h index f9ed4048fc7..47f20f2f879 100644 --- a/source/blender/include/BIF_editconstraint.h +++ b/source/blender/include/BIF_editconstraint.h @@ -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); diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index 4f09ad716d7..4806b23bd57 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -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 */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index fcde95371ac..e06063a11a1 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -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 diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index 0e662c38d31..e4986727ab1 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -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 ); diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c index 9fbd1d9a204..27cfc2fa11c 100644 --- a/source/blender/python/BPY_interface.c +++ b/source/blender/python/BPY_interface.c @@ -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; } } diff --git a/source/blender/python/api2_2x/Constraint.c b/source/blender/python/api2_2x/Constraint.c index 4dddd274a0e..1836c0c6bc2 100644 --- a/source/blender/python/api2_2x/Constraint.c +++ b/source/blender/python/api2_2x/Constraint.c @@ -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: */ diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 55b36ce43db..906160d66c9 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -325,74 +325,6 @@ static void verify_constraint_name_func (void *con_v, void *name_v) allqueue(REDRAWACTION, 0); } -void get_constraint_typestring (char *str, void *con_v) -{ - bConstraint *con= con_v; - - switch (con->type) { - case CONSTRAINT_TYPE_PYTHON: - strcpy(str, "Script"); - return; - case CONSTRAINT_TYPE_CHILDOF: - strcpy(str, "Child Of"); - return; - case CONSTRAINT_TYPE_NULL: - strcpy(str, "Null"); - return; - case CONSTRAINT_TYPE_TRACKTO: - strcpy(str, "Track To"); - return; - case CONSTRAINT_TYPE_MINMAX: - strcpy(str, "Floor"); - return; - case CONSTRAINT_TYPE_KINEMATIC: - strcpy(str, "IK Solver"); - return; - case CONSTRAINT_TYPE_ROTLIKE: - strcpy(str, "Copy Rotation"); - return; - case CONSTRAINT_TYPE_LOCLIKE: - strcpy(str, "Copy Location"); - return; - case CONSTRAINT_TYPE_SIZELIKE: - strcpy(str, "Copy Scale"); - return; - case CONSTRAINT_TYPE_ACTION: - strcpy(str, "Action"); - return; - case CONSTRAINT_TYPE_LOCKTRACK: - strcpy(str, "Locked Track"); - return; - case CONSTRAINT_TYPE_FOLLOWPATH: - strcpy(str, "Follow Path"); - return; - case CONSTRAINT_TYPE_STRETCHTO: - strcpy(str, "Stretch To"); - return; - case CONSTRAINT_TYPE_LOCLIMIT: - strcpy(str, "Limit Location"); - return; - case CONSTRAINT_TYPE_ROTLIMIT: - strcpy(str, "Limit Rotation"); - return; - case CONSTRAINT_TYPE_SIZELIMIT: - strcpy(str, "Limit Scale"); - return; - case CONSTRAINT_TYPE_RIGIDBODYJOINT: - strcpy(str, "Rigid Body"); - return; - case CONSTRAINT_TYPE_CLAMPTO: - strcpy(str, "Clamp To"); - return; - case CONSTRAINT_TYPE_TRANSFORM: - strcpy(str, "Transformation"); - break; - default: - strcpy (str, "Unknown"); - return; - } -} - void const_moveUp(void *ob_v, void *con_v) { bConstraint *con, *constr= con_v; @@ -478,6 +410,11 @@ void autocomplete_vgroup(char *str, void *arg_v) } } +/* some commonly used macros in the constraints drawing code */ +#define is_armature_target(target) (target && target->type==OB_ARMATURE) +#define is_armature_owner(ob) ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE)) +#define is_geom_target(target) (target && (ELEM(target->type, OB_MESH, OB_LATTICE)) ) + /* Helper function for draw constraint - draws constraint space stuff * This function should not be called if no menus are required * owner/target: -1 = don't draw menu; 0= not posemode, 1 = posemode @@ -536,22 +473,24 @@ static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short /* draw panel showing settings for a constraint */ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, short *xco, short *yco) { - Object *ob= OBACT, *target; + Object *ob= OBACT; + bConstraintTypeInfo *cti; uiBut *but; - char typestr[64], *subtarget; + char typestr[64]; short height, width = 265; - short is_armature_target, is_geom_target, is_armature_owner; int rb_col; - target= get_constraint_target(con, &subtarget); - is_armature_target= (target && target->type==OB_ARMATURE); - is_armature_owner= ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE)); - is_geom_target= (target && (ELEM(target->type, OB_MESH, OB_LATTICE)) ); - + cti= constraint_get_typeinfo(con); + if (cti == NULL) { + printf("Argh! No valid constraint type-info... aborting constraint drawing. \n"); + return; + } + else { + strcpy(typestr, cti->name); + } + /* unless button has own callback, it adds this callback to button */ uiBlockSetFunc(block, constraint_active_func, ob, con); - - get_constraint_typestring(typestr, con); /* Draw constraint header */ uiBlockSetEmboss(block, UI_EMBOSSN); @@ -615,11 +554,14 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s case CONSTRAINT_TYPE_PYTHON: { bPythonConstraint *data = con->data; + bConstraintTarget *ct; uiBut *but2; + int tarnum, theight; static int pyconindex=0; char *menustr; - height = 110; + theight = (data->tarnum)? (data->tarnum * 38) : (38); + height = theight + 78; uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40, height-1, NULL, 5.0, 0.0, 12, rb_col, ""); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Script:", *xco+60, *yco-24, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); @@ -632,42 +574,62 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiButSetFunc(but2, validate_pyconstraint_cb, data, &pyconindex); MEM_freeN(menustr); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+60, *yco-48, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + /* draw target(s) */ if (data->flag & PYCON_USETARGETS) { /* Draw target parameters */ - uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-48, 150, 18, &data->tar, "Target Object"); - - if (is_armature_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-66,150,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + for (ct=data->targets.first, tarnum=1; ct; ct=ct->next, tarnum++) { + char tarstr[32]; + + /* target label */ + sprintf(tarstr, "Target %02d:", tarnum); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, tarstr, *xco+60, *yco-48, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + /* target space-selector - per target */ + if (is_armature_target(ct->tar)) { + uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1", + *xco+60, *yco-66, 55, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in"); + } + else { + uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1", + *xco+60, *yco-66, 55, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in"); + } + + uiBlockBeginAlign(block); + /* target object */ + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-48, 150, 18, &ct->tar, "Target Object"); + + /* subtarget */ + if (is_armature_target(ct->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-66,150,18, &ct->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)ct->tar); + } + else if (is_geom_target(ct->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-66,150,18, &ct->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ct->tar); + } + else { + strcpy(ct->subtarget, ""); + } + uiBlockEndAlign(block); } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-66,150,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } - - uiBlockEndAlign(block); } else { /* Draw indication that no target needed */ + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+60, *yco-48, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Not Applicable", *xco+120, *yco-48, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); } /* settings */ uiBlockBeginAlign(block); - but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Options", *xco, *yco-88, (width/2),18, NULL, 0, 24, 0, 0, "Change some of the constraint's settings."); - uiButSetFunc(but, BPY_pyconstraint_settings, data, NULL); - - uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Refresh", *xco+((width/2)+10), *yco-88, (width/2),18, NULL, 0, 24, 0, 0, "Force constraint to refresh it's settings"); + but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Options", *xco, *yco-(52+theight), (width/2),18, NULL, 0, 24, 0, 0, "Change some of the constraint's settings."); + uiButSetFunc(but, BPY_pyconstraint_settings, data, NULL); + + but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Refresh", *xco+((width/2)+10), *yco-(52+theight), (width/2),18, NULL, 0, 24, 0, 0, "Force constraint to refresh it's settings"); + uiButSetFunc(but, update_pyconstraint_cb, ob, con); uiBlockEndAlign(block); /* constraint space settings */ - if ((data->flag & PYCON_USETARGETS)==0) is_armature_target = -1; - draw_constraint_spaceselect(block, con, *xco, *yco-109, is_armature_owner, is_armature_target); + draw_constraint_spaceselect(block, con, *xco, *yco-(73+theight), is_armature_owner(ob), -1); } break; case CONSTRAINT_TYPE_ACTION: @@ -682,48 +644,50 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* Draw target parameters */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); - - if (is_armature_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } uiBlockEndAlign(block); /* Draw action/type buttons */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_actionpoin_but, ID_AC, B_CONSTRAINT_TEST, "AC:", *xco+((width/2)-117), *yco-64, 78, 18, &data->act, "Action containing the keyed motion for this bone"); - uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Key on%t|Loc X%x20|Loc Y%x21|Loc Z%x22|Rot X%x0|Rot Y%x1|Rot Z%x2|Size X%x10|Size Y%x11|Size Z%x12", *xco+((width/2)-117), *yco-84, 78, 18, &data->type, 0, 24, 0, 0, "Specify which transformation channel from the target is used to key the action"); + uiDefIDPoinBut(block, test_actionpoin_but, ID_AC, B_CONSTRAINT_TEST, "AC:", *xco+((width/2)-117), *yco-64, 78, 18, &data->act, "Action containing the keyed motion for this bone"); + uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Key on%t|Loc X%x20|Loc Y%x21|Loc Z%x22|Rot X%x0|Rot Y%x1|Rot Z%x2|Size X%x10|Size Y%x11|Size Z%x12", *xco+((width/2)-117), *yco-84, 78, 18, &data->type, 0, 24, 0, 0, "Specify which transformation channel from the target is used to key the action"); + uiBlockEndAlign(block); /* Draw start/end frame buttons */ uiBlockBeginAlign(block); - uiDefButI(block, NUM, B_CONSTRAINT_TEST, "Start:", *xco+((width/2)-36), *yco-64, 78, 18, &data->start, 1, MAXFRAME, 0.0, 0.0, "Starting frame of the keyed motion"); - uiDefButI(block, NUM, B_CONSTRAINT_TEST, "End:", *xco+((width/2)-36), *yco-84, 78, 18, &data->end, 1, MAXFRAME, 0.0, 0.0, "Ending frame of the keyed motion"); + uiDefButI(block, NUM, B_CONSTRAINT_TEST, "Start:", *xco+((width/2)-36), *yco-64, 78, 18, &data->start, 1, MAXFRAME, 0.0, 0.0, "Starting frame of the keyed motion"); + uiDefButI(block, NUM, B_CONSTRAINT_TEST, "End:", *xco+((width/2)-36), *yco-84, 78, 18, &data->end, 1, MAXFRAME, 0.0, 0.0, "Ending frame of the keyed motion"); + uiBlockEndAlign(block); /* Draw minimum/maximum transform range buttons */ uiBlockBeginAlign(block); - if (data->type < 10) { /* rotation */ - minval = -180.0f; - maxval = 180.0f; - } - else if (data->type < 20) { /* scaling */ - minval = 0.0001f; - maxval = 1000.0f; - } - else { /* location */ - minval = -1000.0f; - maxval = 1000.0f; - } - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Min:", *xco+((width/2)+45), *yco-64, 78, 18, &data->min, minval, maxval, 0, 0, "Minimum value for target channel range"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Max:", *xco+((width/2)+45), *yco-84, 78, 18, &data->max, minval, maxval, 0, 0, "Maximum value for target channel range"); + if (data->type < 10) { /* rotation */ + minval = -180.0f; + maxval = 180.0f; + } + else if (data->type < 20) { /* scaling */ + minval = 0.0001f; + maxval = 1000.0f; + } + else { /* location */ + minval = -1000.0f; + maxval = 1000.0f; + } + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Min:", *xco+((width/2)+45), *yco-64, 78, 18, &data->min, minval, maxval, 0, 0, "Minimum value for target channel range"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Max:", *xco+((width/2)+45), *yco-84, 78, 18, &data->max, minval, maxval, 0, 0, "Maximum value for target channel range"); uiBlockEndAlign(block); /* constraint space settings */ - draw_constraint_spaceselect(block, con, *xco, *yco-104, -1, is_armature_target); + draw_constraint_spaceselect(block, con, *xco, *yco-104, -1, is_armature_target(data->tar)); } break; case CONSTRAINT_TYPE_CHILDOF: @@ -735,53 +699,52 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Parent:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - + /* Draw target parameters */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object to use as Parent"); - - if (is_armature_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone to use as Parent"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } - + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object to use as Parent"); + + if (is_armature_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone to use as Parent"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } uiBlockEndAlign(block); /* Draw triples of channel toggles */ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Use Channel(s):", *xco+65, *yco-64, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); uiBlockBeginAlign(block); - uiDefButBitI(block, TOG, CHILDOF_LOCX, B_CONSTRAINT_TEST, "Loc X", *xco, *yco-84, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects x-location"); - uiDefButBitI(block, TOG, CHILDOF_LOCY, B_CONSTRAINT_TEST, "Loc Y", *xco+normButWidth, *yco-84, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects y-location"); - uiDefButBitI(block, TOG, CHILDOF_LOCZ, B_CONSTRAINT_TEST, "Loc Z", *xco+(normButWidth * 2), *yco-84, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects z-location"); + uiDefButBitI(block, TOG, CHILDOF_LOCX, B_CONSTRAINT_TEST, "Loc X", *xco, *yco-84, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects x-location"); + uiDefButBitI(block, TOG, CHILDOF_LOCY, B_CONSTRAINT_TEST, "Loc Y", *xco+normButWidth, *yco-84, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects y-location"); + uiDefButBitI(block, TOG, CHILDOF_LOCZ, B_CONSTRAINT_TEST, "Loc Z", *xco+(normButWidth * 2), *yco-84, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects z-location"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitI(block, TOG, CHILDOF_ROTX, B_CONSTRAINT_TEST, "Rot X", *xco, *yco-105, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects x-rotation"); - uiDefButBitI(block, TOG, CHILDOF_ROTY, B_CONSTRAINT_TEST, "Rot Y", *xco+normButWidth, *yco-105, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects y-rotation"); - uiDefButBitI(block, TOG, CHILDOF_ROTZ, B_CONSTRAINT_TEST, "Rot Z", *xco+(normButWidth * 2), *yco-105, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects z-rotation"); + uiDefButBitI(block, TOG, CHILDOF_ROTX, B_CONSTRAINT_TEST, "Rot X", *xco, *yco-105, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects x-rotation"); + uiDefButBitI(block, TOG, CHILDOF_ROTY, B_CONSTRAINT_TEST, "Rot Y", *xco+normButWidth, *yco-105, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects y-rotation"); + uiDefButBitI(block, TOG, CHILDOF_ROTZ, B_CONSTRAINT_TEST, "Rot Z", *xco+(normButWidth * 2), *yco-105, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects z-rotation"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitI(block, TOG, CHILDOF_SIZEX, B_CONSTRAINT_TEST, "Scale X", *xco, *yco-126, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects x-scaling"); - uiDefButBitI(block, TOG, CHILDOF_SIZEY, B_CONSTRAINT_TEST, "Scale Y", *xco+normButWidth, *yco-126, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects y-scaling"); - uiDefButBitI(block, TOG, CHILDOF_SIZEZ, B_CONSTRAINT_TEST, "Scale Z", *xco+(normButWidth * 2), *yco-126, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects z-scaling"); + uiDefButBitI(block, TOG, CHILDOF_SIZEX, B_CONSTRAINT_TEST, "Scale X", *xco, *yco-126, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects x-scaling"); + uiDefButBitI(block, TOG, CHILDOF_SIZEY, B_CONSTRAINT_TEST, "Scale Y", *xco+normButWidth, *yco-126, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects y-scaling"); + uiDefButBitI(block, TOG, CHILDOF_SIZEZ, B_CONSTRAINT_TEST, "Scale Z", *xco+(normButWidth * 2), *yco-126, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects z-scaling"); uiBlockEndAlign(block); /* Inverse options */ uiBlockBeginAlign(block); - but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Set Offset", *xco, *yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Calculate current Parent-Inverse Matrix (i.e. restore offset from parent)"); - uiButSetFunc(but, childof_const_setinv, data, NULL); - - but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Clear Offset", *xco+((width/2)+10), *yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Clear Parent-Inverse Matrix (i.e. clear offset from parent)"); - uiButSetFunc(but, childof_const_clearinv, data, NULL); + but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Set Offset", *xco, *yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Calculate current Parent-Inverse Matrix (i.e. restore offset from parent)"); + uiButSetFunc(but, childof_const_setinv, data, NULL); + + but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Clear Offset", *xco+((width/2)+10), *yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Clear Parent-Inverse Matrix (i.e. clear offset from parent)"); + uiButSetFunc(but, childof_const_clearinv, data, NULL); uiBlockEndAlign(block); } break; @@ -796,40 +759,39 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* Draw target parameters */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); - - if (is_armature_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } - + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } uiBlockEndAlign(block); /* Draw XYZ toggles */ uiBlockBeginAlign(block); - but=uiDefButBitI(block, TOG, LOCLIKE_X, B_CONSTRAINT_TEST, "X", *xco+((width/2)-48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy X component"); - but=uiDefButBitI(block, TOG, LOCLIKE_X_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)-16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert X component"); - but=uiDefButBitI(block, TOG, LOCLIKE_Y, B_CONSTRAINT_TEST, "Y", *xco+((width/2)+16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Y component"); - but=uiDefButBitI(block, TOG, LOCLIKE_Y_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Y component"); - but=uiDefButBitI(block, TOG, LOCLIKE_Z, B_CONSTRAINT_TEST, "Z", *xco+((width/2)+96), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Z component"); - but=uiDefButBitI(block, TOG, LOCLIKE_Z_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+128), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Z component"); + uiDefButBitI(block, TOG, LOCLIKE_X, B_CONSTRAINT_TEST, "X", *xco+((width/2)-48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy X component"); + uiDefButBitI(block, TOG, LOCLIKE_X_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)-16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert X component"); + uiDefButBitI(block, TOG, LOCLIKE_Y, B_CONSTRAINT_TEST, "Y", *xco+((width/2)+16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Y component"); + uiDefButBitI(block, TOG, LOCLIKE_Y_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Y component"); + uiDefButBitI(block, TOG, LOCLIKE_Z, B_CONSTRAINT_TEST, "Z", *xco+((width/2)+96), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Z component"); + uiDefButBitI(block, TOG, LOCLIKE_Z_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+128), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Z component"); uiBlockEndAlign(block); /* Draw options */ uiDefButBitI(block, TOG, LOCLIKE_OFFSET, B_CONSTRAINT_TEST, "Offset", *xco, *yco-89, (width/2), 18, &data->flag, 0, 24, 0, 0, "Add original location onto copied location"); - if (is_armature_target) { + if (is_armature_target(data->tar)) { uiDefButBitI(block, TOG, LOCLIKE_TIP, B_CONSTRAINT_TEST, "Target Bone Tail", *xco+(width/2), *yco-89, (width/2), 18, &data->flag, 0, 24, 0, 0, "Copy Location of Target Bone's Tail"); } /* constraint space settings */ - draw_constraint_spaceselect(block, con, *xco, *yco-109, is_armature_owner, is_armature_target); + draw_constraint_spaceselect(block, con, *xco, *yco-109, is_armature_owner(ob), is_armature_target(data->tar)); } break; case CONSTRAINT_TYPE_ROTLIKE: @@ -840,37 +802,36 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - + /* Draw target parameters */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); - - if (is_armature_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } - + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } uiBlockEndAlign(block); /* Draw XYZ toggles */ uiBlockBeginAlign(block); - but=uiDefButBitI(block, TOG, ROTLIKE_X, B_CONSTRAINT_TEST, "X", *xco+((width/2)-48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy X component"); - but=uiDefButBitI(block, TOG, ROTLIKE_X_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)-16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert X component"); - but=uiDefButBitI(block, TOG, ROTLIKE_Y, B_CONSTRAINT_TEST, "Y", *xco+((width/2)+16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Y component"); - but=uiDefButBitI(block, TOG, ROTLIKE_Y_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Y component"); - but=uiDefButBitI(block, TOG, ROTLIKE_Z, B_CONSTRAINT_TEST, "Z", *xco+((width/2)+96), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Z component"); - but=uiDefButBitI(block, TOG, ROTLIKE_Z_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+128), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Z component"); + uiDefButBitI(block, TOG, ROTLIKE_X, B_CONSTRAINT_TEST, "X", *xco+((width/2)-48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy X component"); + uiDefButBitI(block, TOG, ROTLIKE_X_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)-16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert X component"); + uiDefButBitI(block, TOG, ROTLIKE_Y, B_CONSTRAINT_TEST, "Y", *xco+((width/2)+16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Y component"); + uiDefButBitI(block, TOG, ROTLIKE_Y_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Y component"); + uiDefButBitI(block, TOG, ROTLIKE_Z, B_CONSTRAINT_TEST, "Z", *xco+((width/2)+96), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Z component"); + uiDefButBitI(block, TOG, ROTLIKE_Z_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+128), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Z component"); uiBlockEndAlign(block); /* constraint space settings */ - draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner, is_armature_target); + draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner(ob), is_armature_target(data->tar)); } break; case CONSTRAINT_TYPE_SIZELIKE: @@ -885,31 +846,30 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* Draw target parameters */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); - - if (is_armature_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } - + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } uiBlockEndAlign(block); /* Draw XYZ toggles */ uiBlockBeginAlign(block); - but=uiDefButBitI(block, TOG, SIZELIKE_X, B_CONSTRAINT_TEST, "X", *xco+((width/2)-48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy X component"); - but=uiDefButBitI(block, TOG, SIZELIKE_Y, B_CONSTRAINT_TEST, "Y", *xco+((width/2)-16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Y component"); - but=uiDefButBitI(block, TOG, SIZELIKE_Z, B_CONSTRAINT_TEST, "Z", *xco+((width/2)+16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Z component"); + uiDefButBitI(block, TOG, SIZELIKE_X, B_CONSTRAINT_TEST, "X", *xco+((width/2)-48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy X component"); + uiDefButBitI(block, TOG, SIZELIKE_Y, B_CONSTRAINT_TEST, "Y", *xco+((width/2)-16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Y component"); + uiDefButBitI(block, TOG, SIZELIKE_Z, B_CONSTRAINT_TEST, "Z", *xco+((width/2)+16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Z component"); uiBlockEndAlign(block); /* constraint space settings */ - draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner, is_armature_target); + draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner(ob), is_armature_target(data->tar)); } break; case CONSTRAINT_TYPE_KINEMATIC: @@ -925,33 +885,38 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefButBitS(block, TOG, CONSTRAINT_IK_ROT, B_CONSTRAINT_TEST, "Rot", *xco, *yco-24,60,19, &data->flag, 0, 0, 0, 0, "Chain follows rotation of target"); uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 19, &data->tar, "Target Object"); - - if (is_armature_target) { - but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,19, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } - - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, CONSTRAINT_IK_TIP, B_CONSTRAINT_TEST, "Use Tail", *xco, *yco-64, 137, 19, &data->flag, 0, 0, 0, 0, "Include Bone's tail as last element in Chain"); - uiDefButI(block, NUM, B_CONSTRAINT_TEST, "ChainLen:", *xco, *yco-84,137,19, &data->rootbone, 0, 255, 0, 0, "If not zero, the amount of bones in this chain"); + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 19, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,19, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } + uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "PosW ", *xco+147, *yco-64, 137, 19, &data->weight, 0.01, 1.0, 2, 2, "For Tree-IK: weight of position control for this target"); - uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "RotW ", *xco+147, *yco-84, 137, 19, &data->orientweight, 0.01, 1.0, 2, 2, "For Tree-IK: Weight of orientation control for this target"); - - uiBlockBeginAlign(block); - uiDefButS(block, NUM, B_CONSTRAINT_TEST, "Iterations:", *xco, *yco-109, 137, 19, &data->iterations, 1, 10000, 0, 0, "Maximum number of solving iterations"); - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, CONSTRAINT_IK_STRETCH, B_CONSTRAINT_TEST, "Stretch", *xco+147, *yco-109,137,19, &data->flag, 0, 0, 0, 0, "Enable IK stretching"); + uiDefButBitS(block, TOG, CONSTRAINT_IK_TIP, B_CONSTRAINT_TEST, "Use Tail", *xco, *yco-64, 137, 19, &data->flag, 0, 0, 0, 0, "Include Bone's tail as last element in Chain"); + uiDefButI(block, NUM, B_CONSTRAINT_TEST, "ChainLen:", *xco, *yco-84,137,19, &data->rootbone, 0, 255, 0, 0, "If not zero, the amount of bones in this chain"); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); + uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "PosW ", *xco+147, *yco-64, 137, 19, &data->weight, 0.01, 1.0, 2, 2, "For Tree-IK: weight of position control for this target"); + uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "RotW ", *xco+147, *yco-84, 137, 19, &data->orientweight, 0.01, 1.0, 2, 2, "For Tree-IK: Weight of orientation control for this target"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefButS(block, NUM, B_CONSTRAINT_TEST, "Iterations:", *xco, *yco-109, 137, 19, &data->iterations, 1, 10000, 0, 0, "Maximum number of solving iterations"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, CONSTRAINT_IK_STRETCH, B_CONSTRAINT_TEST, "Stretch", *xco+147, *yco-109,137,19, &data->flag, 0, 0, 0, 0, "Enable IK stretching"); + uiBlockEndAlign(block); } break; case CONSTRAINT_TYPE_TRACKTO: @@ -962,95 +927,93 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - + /* Draw target parameters */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); - - if (is_armature_target) { - but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } - + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Align:", *xco+5, *yco-42, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - - uiDefButBitI(block, TOG, 1, B_CONSTRAINT_TEST, "TargetZ", *xco+60, *yco-42, 50, 18, &data->flags, 0, 1, 0, 0, "Target Z axis, not world Z axis, will constrain up direction"); - uiBlockEndAlign(block); - - uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "To:", *xco+12, *yco-64, 25, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+39, *yco-64,17,18, &data->reserved1, 12.0, 0.0, 0, 0, "X axis points to the target object"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+56, *yco-64,17,18, &data->reserved1, 12.0, 1.0, 0, 0, "Y axis points to the target object"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+73, *yco-64,17,18, &data->reserved1, 12.0, 2.0, 0, 0, "Z axis points to the target object"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-X", *xco+90, *yco-64,24,18, &data->reserved1, 12.0, 3.0, 0, 0, "-X axis points to the target object"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Y", *xco+114, *yco-64,24,18, &data->reserved1, 12.0, 4.0, 0, 0, "-Y axis points to the target object"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Z", *xco+138, *yco-64,24,18, &data->reserved1, 12.0, 5.0, 0, 0, "-Z axis points to the target object"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Align:", *xco+5, *yco-42, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + uiDefButBitI(block, TOG, 1, B_CONSTRAINT_TEST, "TargetZ", *xco+60, *yco-42, 50, 18, &data->flags, 0, 1, 0, 0, "Target Z axis, not world Z axis, will constrain up direction"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Up:", *xco+174, *yco-64, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "To:", *xco+12, *yco-64, 25, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+39, *yco-64,17,18, &data->reserved1, 12.0, 0.0, 0, 0, "X axis points to the target object"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+56, *yco-64,17,18, &data->reserved1, 12.0, 1.0, 0, 0, "Y axis points to the target object"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+73, *yco-64,17,18, &data->reserved1, 12.0, 2.0, 0, 0, "Z axis points to the target object"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-X", *xco+90, *yco-64,24,18, &data->reserved1, 12.0, 3.0, 0, 0, "-X axis points to the target object"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Y", *xco+114, *yco-64,24,18, &data->reserved1, 12.0, 4.0, 0, 0, "-Y axis points to the target object"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Z", *xco+138, *yco-64,24,18, &data->reserved1, 12.0, 5.0, 0, 0, "-Z axis points to the target object"); + uiBlockEndAlign(block); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+204, *yco-64,17,18, &data->reserved2, 13.0, 0.0, 0, 0, "X axis points upward"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+221, *yco-64,17,18, &data->reserved2, 13.0, 1.0, 0, 0, "Y axis points upward"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+238, *yco-64,17,18, &data->reserved2, 13.0, 2.0, 0, 0, "Z axis points upward"); + uiBlockBeginAlign(block); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Up:", *xco+174, *yco-64, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+204, *yco-64,17,18, &data->reserved2, 13.0, 0.0, 0, 0, "X axis points upward"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+221, *yco-64,17,18, &data->reserved2, 13.0, 1.0, 0, 0, "Y axis points upward"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+238, *yco-64,17,18, &data->reserved2, 13.0, 2.0, 0, 0, "Z axis points upward"); uiBlockEndAlign(block); /* constraint space settings */ - draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner, is_armature_target); + draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner(ob), is_armature_target(data->tar)); } break; case CONSTRAINT_TYPE_MINMAX: { bMinMaxConstraint *data = con->data; - + height = 66; uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Offset:", *xco, *yco-44, 100, 18, &data->offset, -100, 100, 100.0, 0.0, "Offset from the position of the object center"); - + /* Draw target parameters */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); - - if (is_armature_target) { - but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } - + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } uiBlockEndAlign(block); - - but=uiDefButI(block, TOG|BIT|0, B_CONSTRAINT_TEST, "Sticky", *xco, *yco-24, 44, 18, &data->flag, 0, 24, 0, 0, "Immobilize object while constrained"); - but=uiDefButI(block, TOG|BIT|2, B_CONSTRAINT_TEST, "Use Rot", *xco+44, *yco-24, 64, 18, &data->flag, 0, 24, 0, 0, "Use target object rotation"); + + uiDefButBitI(block, TOG, 0, B_CONSTRAINT_TEST, "Sticky", *xco, *yco-24, 44, 18, &data->flag, 0, 24, 0, 0, "Immobilize object while constrained"); + uiDefButBitI(block, TOG, 2, B_CONSTRAINT_TEST, "Use Rot", *xco+44, *yco-24, 64, 18, &data->flag, 0, 24, 0, 0, "Use target object rotation"); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Max/Min:", *xco-8, *yco-64, 54, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - + uiBlockBeginAlign(block); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+51, *yco-64,17,18, &data->minmaxflag, 12.0, 0.0, 0, 0, "Will not pass below X of target"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+67, *yco-64,17,18, &data->minmaxflag, 12.0, 1.0, 0, 0, "Will not pass below Y of target"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+85, *yco-64,17,18, &data->minmaxflag, 12.0, 2.0, 0, 0, "Will not pass below Z of target"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-X", *xco+102, *yco-64,24,18, &data->minmaxflag, 12.0, 3.0, 0, 0, "Will not pass above X of target"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Y", *xco+126, *yco-64,24,18, &data->minmaxflag, 12.0, 4.0, 0, 0, "Will not pass above Y of target"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Z", *xco+150, *yco-64,24,18, &data->minmaxflag, 12.0, 5.0, 0, 0, "Will not pass above Z of target"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"X", *xco+51, *yco-64,17,18, &data->minmaxflag, 12.0, 0.0, 0, 0, "Will not pass below X of target"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Y", *xco+67, *yco-64,17,18, &data->minmaxflag, 12.0, 1.0, 0, 0, "Will not pass below Y of target"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Z", *xco+85, *yco-64,17,18, &data->minmaxflag, 12.0, 2.0, 0, 0, "Will not pass below Z of target"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-X", *xco+102, *yco-64,24,18, &data->minmaxflag, 12.0, 3.0, 0, 0, "Will not pass above X of target"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Y", *xco+126, *yco-64,24,18, &data->minmaxflag, 12.0, 4.0, 0, 0, "Will not pass above Y of target"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Z", *xco+150, *yco-64,24,18, &data->minmaxflag, 12.0, 5.0, 0, 0, "Will not pass above Z of target"); uiBlockEndAlign(block); } break; @@ -1064,39 +1027,38 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* Draw target parameters */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); - - if (is_armature_target) { - but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } - + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "To:", *xco+12, *yco-64, 25, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+39, *yco-64,17,18, &data->trackflag, 12.0, 0.0, 0, 0, "X axis points to the target object"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+56, *yco-64,17,18, &data->trackflag, 12.0, 1.0, 0, 0, "Y axis points to the target object"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+73, *yco-64,17,18, &data->trackflag, 12.0, 2.0, 0, 0, "Z axis points to the target object"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-X", *xco+90, *yco-64,24,18, &data->trackflag, 12.0, 3.0, 0, 0, "-X axis points to the target object"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Y", *xco+114, *yco-64,24,18, &data->trackflag, 12.0, 4.0, 0, 0, "-Y axis points to the target object"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Z", *xco+138, *yco-64,24,18, &data->trackflag, 12.0, 5.0, 0, 0, "-Z axis points to the target object"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "To:", *xco+12, *yco-64, 25, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"X", *xco+39, *yco-64,17,18, &data->trackflag, 12.0, 0.0, 0, 0, "X axis points to the target object"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Y", *xco+56, *yco-64,17,18, &data->trackflag, 12.0, 1.0, 0, 0, "Y axis points to the target object"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Z", *xco+73, *yco-64,17,18, &data->trackflag, 12.0, 2.0, 0, 0, "Z axis points to the target object"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-X", *xco+90, *yco-64,24,18, &data->trackflag, 12.0, 3.0, 0, 0, "-X axis points to the target object"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Y", *xco+114, *yco-64,24,18, &data->trackflag, 12.0, 4.0, 0, 0, "-Y axis points to the target object"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Z", *xco+138, *yco-64,24,18, &data->trackflag, 12.0, 5.0, 0, 0, "-Z axis points to the target object"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Lock:", *xco+166, *yco-64, 38, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+204, *yco-64,17,18, &data->lockflag, 13.0, 0.0, 0, 0, "X axis is locked"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+221, *yco-64,17,18, &data->lockflag, 13.0, 1.0, 0, 0, "Y axis is locked"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+238, *yco-64,17,18, &data->lockflag, 13.0, 2.0, 0, 0, "Z axis is locked"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Lock:", *xco+166, *yco-64, 38, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"X", *xco+204, *yco-64,17,18, &data->lockflag, 13.0, 0.0, 0, 0, "X axis is locked"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Y", *xco+221, *yco-64,17,18, &data->lockflag, 13.0, 1.0, 0, 0, "Y axis is locked"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Z", *xco+238, *yco-64,17,18, &data->lockflag, 13.0, 2.0, 0, 0, "Z axis is locked"); uiBlockEndAlign(block); } break; @@ -1113,28 +1075,28 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); /* Draw Curve Follow toggle */ - but=uiDefButBitI(block, TOG, 1, B_CONSTRAINT_TEST, "CurveFollow", *xco+39, *yco-44, 100, 18, &data->followflag, 0, 24, 0, 0, "Object will follow the heading and banking of the curve"); + uiDefButBitI(block, TOG, 1, B_CONSTRAINT_TEST, "CurveFollow", *xco+39, *yco-44, 100, 18, &data->followflag, 0, 24, 0, 0, "Object will follow the heading and banking of the curve"); /* Draw Offset number button */ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Offset:", *xco+155, *yco-44, 100, 18, &data->offset, -MAXFRAMEF, MAXFRAMEF, 100.0, 0.0, "Offset from the position corresponding to the time frame"); uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Fw:", *xco+12, *yco-64, 27, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+39, *yco-64,17,18, &data->trackflag, 12.0, 0.0, 0, 0, "The axis that points forward along the path"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+56, *yco-64,17,18, &data->trackflag, 12.0, 1.0, 0, 0, "The axis that points forward along the path"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+73, *yco-64,17,18, &data->trackflag, 12.0, 2.0, 0, 0, "The axis that points forward along the path"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-X", *xco+90, *yco-64,24,18, &data->trackflag, 12.0, 3.0, 0, 0, "The axis that points forward along the path"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Y", *xco+114, *yco-64,24,18, &data->trackflag, 12.0, 4.0, 0, 0, "The axis that points forward along the path"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Z", *xco+138, *yco-64,24,18, &data->trackflag, 12.0, 5.0, 0, 0, "The axis that points forward along the path"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Fw:", *xco+12, *yco-64, 27, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"X", *xco+39, *yco-64,17,18, &data->trackflag, 12.0, 0.0, 0, 0, "The axis that points forward along the path"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Y", *xco+56, *yco-64,17,18, &data->trackflag, 12.0, 1.0, 0, 0, "The axis that points forward along the path"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Z", *xco+73, *yco-64,17,18, &data->trackflag, 12.0, 2.0, 0, 0, "The axis that points forward along the path"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-X", *xco+90, *yco-64,24,18, &data->trackflag, 12.0, 3.0, 0, 0, "The axis that points forward along the path"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Y", *xco+114, *yco-64,24,18, &data->trackflag, 12.0, 4.0, 0, 0, "The axis that points forward along the path"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Z", *xco+138, *yco-64,24,18, &data->trackflag, 12.0, 5.0, 0, 0, "The axis that points forward along the path"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Up:", *xco+174, *yco-64, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+204, *yco-64,17,18, &data->upflag, 13.0, 0.0, 0, 0, "The axis that points upward"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+221, *yco-64,17,18, &data->upflag, 13.0, 1.0, 0, 0, "The axis that points upward"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+238, *yco-64,17,18, &data->upflag, 13.0, 2.0, 0, 0, "The axis that points upward"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Up:", *xco+174, *yco-64, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"X", *xco+204, *yco-64,17,18, &data->upflag, 13.0, 0.0, 0, 0, "The axis that points upward"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Y", *xco+221, *yco-64,17,18, &data->upflag, 13.0, 1.0, 0, 0, "The axis that points upward"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Z", *xco+238, *yco-64,17,18, &data->upflag, 13.0, 2.0, 0, 0, "The axis that points upward"); uiBlockEndAlign(block); } break; @@ -1146,46 +1108,44 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - + /* Draw target parameters */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); - - if (is_armature_target) { - but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy (data->subtarget, ""); - } - + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } uiBlockEndAlign(block); - + uiBlockBeginAlign(block); - uiDefButF(block,BUTM,B_CONSTRAINT_TEST,"R",*xco, *yco-60,20,18,&(data->orglength),0.0,0,0,0,"Recalculate RLength"); - uiDefButF(block,NUM,B_CONSTRAINT_TEST,"Rest Length:",*xco+18, *yco-60,237,18,&(data->orglength),0.0,100,0.5,0.5,"Length at Rest Position"); + uiDefButF(block,BUTM,B_CONSTRAINT_TEST,"R",*xco, *yco-60,20,18,&(data->orglength),0.0,0,0,0,"Recalculate RLength"); + uiDefButF(block,NUM,B_CONSTRAINT_TEST,"Rest Length:",*xco+18, *yco-60,237,18,&(data->orglength),0.0,100,0.5,0.5,"Length at Rest Position"); uiBlockEndAlign(block); - + uiDefButF(block,NUM,B_CONSTRAINT_TEST,"Volume Variation:",*xco+18, *yco-82,237,18,&(data->bulge),0.0,100,0.5,0.5,"Factor between volume variation and stretching"); - - uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Vol:",*xco+14, *yco-104,30,18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"XZ", *xco+44, *yco-104,30,18, &data->volmode, 12.0, 0.0, 0, 0, "Keep Volume: Scaling X & Z"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+74, *yco-104,20,18, &data->volmode, 12.0, 1.0, 0, 0, "Keep Volume: Scaling X"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+94, *yco-104,20,18, &data->volmode, 12.0, 2.0, 0, 0, "Keep Volume: Scaling Z"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"NONE", *xco+114, *yco-104,50,18, &data->volmode, 12.0, 3.0, 0, 0, "Ignore Volume"); - uiBlockEndAlign(block); - uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST,"Plane:",*xco+175, *yco-104,40,18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+215, *yco-104,20,18, &data->plane, 12.0, 0.0, 0, 0, "Keep X axis"); - uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+235, *yco-104,20,18, &data->plane, 12.0, 2.0, 0, 0, "Keep Z axis"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Vol:",*xco+14, *yco-104,30,18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"XZ", *xco+44, *yco-104,30,18, &data->volmode, 12.0, 0.0, 0, 0, "Keep Volume: Scaling X & Z"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+74, *yco-104,20,18, &data->volmode, 12.0, 1.0, 0, 0, "Keep Volume: Scaling X"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+94, *yco-104,20,18, &data->volmode, 12.0, 2.0, 0, 0, "Keep Volume: Scaling Z"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"NONE", *xco+114, *yco-104,50,18, &data->volmode, 12.0, 3.0, 0, 0, "Ignore Volume"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST,"Plane:",*xco+175, *yco-104,40,18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+215, *yco-104,20,18, &data->plane, 12.0, 0.0, 0, 0, "Keep X axis"); + uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+235, *yco-104,20,18, &data->plane, 12.0, 2.0, 0, 0, "Keep Z axis"); uiBlockEndAlign(block); } break; @@ -1201,37 +1161,37 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* Draw Pairs of LimitToggle+LimitValue */ uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_XMIN, B_CONSTRAINT_TEST, "minX", *xco, *yco-28, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-28, (textButWidth-5), 18, &(data->xmin), -1000, 1000, 0.1,0.5,"Lowest x value to allow"); + uiDefButBitS(block, TOG, LIMIT_XMIN, B_CONSTRAINT_TEST, "minX", *xco, *yco-28, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-28, (textButWidth-5), 18, &(data->xmin), -1000, 1000, 0.1,0.5,"Lowest x value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_XMAX, B_CONSTRAINT_TEST, "maxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-28, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum x value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-28, (textButWidth-5), 18, &(data->xmax), -1000, 1000, 0.1,0.5,"Highest x value to allow"); + uiDefButBitS(block, TOG, LIMIT_XMAX, B_CONSTRAINT_TEST, "maxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-28, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum x value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-28, (textButWidth-5), 18, &(data->xmax), -1000, 1000, 0.1,0.5,"Highest x value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_YMIN, B_CONSTRAINT_TEST, "minY", *xco, *yco-50, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-50, (textButWidth-5), 18, &(data->ymin), -1000, 1000, 0.1,0.5,"Lowest y value to allow"); + uiDefButBitS(block, TOG, LIMIT_YMIN, B_CONSTRAINT_TEST, "minY", *xco, *yco-50, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-50, (textButWidth-5), 18, &(data->ymin), -1000, 1000, 0.1,0.5,"Lowest y value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_YMAX, B_CONSTRAINT_TEST, "maxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-50, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum y value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-50, (textButWidth-5), 18, &(data->ymax), -1000, 1000, 0.1,0.5,"Highest y value to allow"); + uiDefButBitS(block, TOG, LIMIT_YMAX, B_CONSTRAINT_TEST, "maxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-50, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum y value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-50, (textButWidth-5), 18, &(data->ymax), -1000, 1000, 0.1,0.5,"Highest y value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_ZMIN, B_CONSTRAINT_TEST, "minZ", *xco, *yco-72, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-72, (textButWidth-5), 18, &(data->zmin), -1000, 1000, 0.1,0.5,"Lowest z value to allow"); + uiDefButBitS(block, TOG, LIMIT_ZMIN, B_CONSTRAINT_TEST, "minZ", *xco, *yco-72, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-72, (textButWidth-5), 18, &(data->zmin), -1000, 1000, 0.1,0.5,"Lowest z value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_ZMAX, B_CONSTRAINT_TEST, "maxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-72, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum z value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-72, (textButWidth-5), 18, &(data->zmax), -1000, 1000, 0.1,0.5,"Highest z value to allow"); + uiDefButBitS(block, TOG, LIMIT_ZMAX, B_CONSTRAINT_TEST, "maxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-72, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum z value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-72, (textButWidth-5), 18, &(data->zmax), -1000, 1000, 0.1,0.5,"Highest z value to allow"); uiBlockEndAlign(block); /* constraint space settings */ - draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner, -1); + draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner(ob), -1); } break; case CONSTRAINT_TYPE_ROTLIMIT: @@ -1245,25 +1205,25 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* Draw Pairs of LimitToggle+LimitValue */ uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_XROT, B_CONSTRAINT_TEST, "LimitX", *xco, *yco-28, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Limit rotation on x-axis"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min:", *xco+normButWidth, *yco-28, normButWidth, 18, &(data->xmin), -360, 360, 0.1,0.5,"Lowest x value to allow"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max:", *xco+(normButWidth * 2), *yco-28, normButWidth, 18, &(data->xmax), -360, 360, 0.1,0.5,"Highest x value to allow"); + uiDefButBitS(block, TOG, LIMIT_XROT, B_CONSTRAINT_TEST, "LimitX", *xco, *yco-28, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Limit rotation on x-axis"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min:", *xco+normButWidth, *yco-28, normButWidth, 18, &(data->xmin), -360, 360, 0.1,0.5,"Lowest x value to allow"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max:", *xco+(normButWidth * 2), *yco-28, normButWidth, 18, &(data->xmax), -360, 360, 0.1,0.5,"Highest x value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_YROT, B_CONSTRAINT_TEST, "LimitY", *xco, *yco-50, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Limit rotation on y-axis"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min:", *xco+normButWidth, *yco-50, normButWidth, 18, &(data->ymin), -360, 360, 0.1,0.5,"Lowest y value to allow"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max:", *xco+(normButWidth * 2), *yco-50, normButWidth, 18, &(data->ymax), -360, 360, 0.1,0.5,"Highest y value to allow"); + uiDefButBitS(block, TOG, LIMIT_YROT, B_CONSTRAINT_TEST, "LimitY", *xco, *yco-50, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Limit rotation on y-axis"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min:", *xco+normButWidth, *yco-50, normButWidth, 18, &(data->ymin), -360, 360, 0.1,0.5,"Lowest y value to allow"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max:", *xco+(normButWidth * 2), *yco-50, normButWidth, 18, &(data->ymax), -360, 360, 0.1,0.5,"Highest y value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_ZROT, B_CONSTRAINT_TEST, "LimitZ", *xco, *yco-72, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Limit rotation on z-axis"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min:", *xco+normButWidth, *yco-72, normButWidth, 18, &(data->zmin), -360, 360, 0.1,0.5,"Lowest z value to allow"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max:", *xco+(normButWidth * 2), *yco-72, normButWidth, 18, &(data->zmax), -360, 360, 0.1,0.5,"Highest z value to allow"); + uiDefButBitS(block, TOG, LIMIT_ZROT, B_CONSTRAINT_TEST, "LimitZ", *xco, *yco-72, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Limit rotation on z-axis"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min:", *xco+normButWidth, *yco-72, normButWidth, 18, &(data->zmin), -360, 360, 0.1,0.5,"Lowest z value to allow"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max:", *xco+(normButWidth * 2), *yco-72, normButWidth, 18, &(data->zmax), -360, 360, 0.1,0.5,"Highest z value to allow"); uiBlockEndAlign(block); /* constraint space settings */ - draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner, -1); + draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner(ob), -1); } break; case CONSTRAINT_TYPE_SIZELIMIT: @@ -1279,39 +1239,39 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* Draw Pairs of LimitToggle+LimitValue */ uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_XMIN, B_CONSTRAINT_TEST, "minX", *xco, *yco-28, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-28, (textButWidth-5), 18, &(data->xmin), 0.0001, 1000, 0.1,0.5,"Lowest x value to allow"); + uiDefButBitS(block, TOG, LIMIT_XMIN, B_CONSTRAINT_TEST, "minX", *xco, *yco-28, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-28, (textButWidth-5), 18, &(data->xmin), 0.0001, 1000, 0.1,0.5,"Lowest x value to allow"); uiBlockEndAlign(block); - + uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_XMAX, B_CONSTRAINT_TEST, "maxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-28, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum x value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-28, (textButWidth-5), 18, &(data->xmax), 0.0001, 1000, 0.1,0.5,"Highest x value to allow"); + uiDefButBitS(block, TOG, LIMIT_XMAX, B_CONSTRAINT_TEST, "maxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-28, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum x value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-28, (textButWidth-5), 18, &(data->xmax), 0.0001, 1000, 0.1,0.5,"Highest x value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_YMIN, B_CONSTRAINT_TEST, "minY", *xco, *yco-50, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-50, (textButWidth-5), 18, &(data->ymin), 0.0001, 1000, 0.1,0.5,"Lowest y value to allow"); + uiDefButBitS(block, TOG, LIMIT_YMIN, B_CONSTRAINT_TEST, "minY", *xco, *yco-50, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-50, (textButWidth-5), 18, &(data->ymin), 0.0001, 1000, 0.1,0.5,"Lowest y value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_YMAX, B_CONSTRAINT_TEST, "maxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-50, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum y value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-50, (textButWidth-5), 18, &(data->ymax), 0.0001, 1000, 0.1,0.5,"Highest y value to allow"); + uiDefButBitS(block, TOG, LIMIT_YMAX, B_CONSTRAINT_TEST, "maxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-50, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum y value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-50, (textButWidth-5), 18, &(data->ymax), 0.0001, 1000, 0.1,0.5,"Highest y value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_ZMIN, B_CONSTRAINT_TEST, "minZ", *xco, *yco-72, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-72, (textButWidth-5), 18, &(data->zmin), 0.0001, 1000, 0.1,0.5,"Lowest z value to allow"); + uiDefButBitS(block, TOG, LIMIT_ZMIN, B_CONSTRAINT_TEST, "minZ", *xco, *yco-72, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-72, (textButWidth-5), 18, &(data->zmin), 0.0001, 1000, 0.1,0.5,"Lowest z value to allow"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, LIMIT_ZMAX, B_CONSTRAINT_TEST, "maxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-72, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum z value"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-72, (textButWidth-5), 18, &(data->zmax), 0.0001, 1000, 0.1,0.5,"Highest z value to allow"); + uiDefButBitS(block, TOG, LIMIT_ZMAX, B_CONSTRAINT_TEST, "maxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-72, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum z value"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-72, (textButWidth-5), 18, &(data->zmax), 0.0001, 1000, 0.1,0.5,"Highest z value to allow"); uiBlockEndAlign(block); /* constraint space settings */ - draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner, -1); + draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner(ob), -1); } break; case CONSTRAINT_TYPE_RIGIDBODYJOINT: @@ -1324,7 +1284,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s int togButWidth = 70; int offsetY = 150; int textButWidth = ((width/2)-togButWidth); - + uiDefButI(block, MENU, B_CONSTRAINT_TEST, "Joint Types%t|Ball%x1|Hinge%x2|Cone Twist%x4|Generic (experimental)%x12",//|Extra Force%x6", *xco, *yco-25, 150, 18, &data->type, 0, 0, 0, 0, "Choose the joint type"); height = 140; @@ -1334,10 +1294,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s height = 200; uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); - + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "toObject:", *xco, *yco-50, 130, 18, &data->tar, "Child Object"); uiDefButBitS(block, TOG, CONSTRAINT_DRAW_PIVOT, B_CONSTRAINT_TEST, "ShowPivot", *xco+135, *yco-50, 130, 18, &data->flag, 0, 24, 0, 0, "Show pivot position and rotation"); - + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Pivot X:", *xco, *yco-75, 130, 18, &data->pivX, -1000, 1000, 100, 0.0, "Offset pivot on X"); uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Pivot Y:", *xco, *yco-100, 130, 18, &data->pivY, -1000, 1000, 100, 0.0, "Offset pivot on Y"); uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Pivot Z:", *xco, *yco-125, 130, 18, &data->pivZ, -1000, 1000, 100, 0.0, "Offset pivot on z"); @@ -1349,58 +1309,69 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s if (data->type==CONSTRAINT_RB_GENERIC6DOF) { /* Draw Pairs of LimitToggle+LimitValue */ uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 1, B_CONSTRAINT_TEST, "LinMinX", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[0]), -extremeLin, extremeLin, 0.1,0.5,"min x limit"); - + uiDefButBitS(block, TOG, 1, B_CONSTRAINT_TEST, "LinMinX", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[0]), -extremeLin, extremeLin, 0.1,0.5,"min x limit"); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 1, B_CONSTRAINT_TEST, "LinMaxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum x limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[0]), -extremeLin, extremeLin, 0.1,0.5,"max x limit"); - + uiDefButBitS(block, TOG, 1, B_CONSTRAINT_TEST, "LinMaxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum x limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[0]), -extremeLin, extremeLin, 0.1,0.5,"max x limit"); + uiBlockEndAlign(block); + offsetY += 20; uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 2, B_CONSTRAINT_TEST, "LinMinY", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[1]), -extremeLin, extremeLin, 0.1,0.5,"min y limit"); - + uiDefButBitS(block, TOG, 2, B_CONSTRAINT_TEST, "LinMinY", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[1]), -extremeLin, extremeLin, 0.1,0.5,"min y limit"); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 2, B_CONSTRAINT_TEST, "LinMaxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum y limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[1]), -extremeLin, extremeLin, 0.1,0.5,"max y limit"); - + uiDefButBitS(block, TOG, 2, B_CONSTRAINT_TEST, "LinMaxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum y limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[1]), -extremeLin, extremeLin, 0.1,0.5,"max y limit"); + uiBlockEndAlign(block); + offsetY += 20; uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 4, B_CONSTRAINT_TEST, "LinMinZ", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[2]), -extremeLin, extremeLin, 0.1,0.5,"min z limit"); - + uiDefButBitS(block, TOG, 4, B_CONSTRAINT_TEST, "LinMinZ", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[2]), -extremeLin, extremeLin, 0.1,0.5,"min z limit"); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 4, B_CONSTRAINT_TEST, "LinMaxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum z limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[2]), -extremeLin, extremeLin, 0.1,0.5,"max z limit"); + uiDefButBitS(block, TOG, 4, B_CONSTRAINT_TEST, "LinMaxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum z limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[2]), -extremeLin, extremeLin, 0.1,0.5,"max z limit"); + uiBlockEndAlign(block); offsetY += 20; } if ((data->type==CONSTRAINT_RB_GENERIC6DOF) || (data->type==CONSTRAINT_RB_CONETWIST)) { /* Draw Pairs of LimitToggle+LimitValue */ uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 8, B_CONSTRAINT_TEST, "AngMinX", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[3]), -extremeAngX, extremeAngX, 0.1,0.5,"min x limit"); + uiDefButBitS(block, TOG, 8, B_CONSTRAINT_TEST, "AngMinX", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[3]), -extremeAngX, extremeAngX, 0.1,0.5,"min x limit"); + uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 8, B_CONSTRAINT_TEST, "AngMaxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum x limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[3]), -extremeAngX, extremeAngX, 0.1,0.5,"max x limit"); - + uiDefButBitS(block, TOG, 8, B_CONSTRAINT_TEST, "AngMaxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum x limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[3]), -extremeAngX, extremeAngX, 0.1,0.5,"max x limit"); + uiBlockEndAlign(block); + offsetY += 20; uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 16, B_CONSTRAINT_TEST, "AngMinY", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[4]), -extremeAngY, extremeAngY, 0.1,0.5,"min y limit"); - + uiDefButBitS(block, TOG, 16, B_CONSTRAINT_TEST, "AngMinY", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[4]), -extremeAngY, extremeAngY, 0.1,0.5,"min y limit"); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 16, B_CONSTRAINT_TEST, "AngMaxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum y limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[4]), -extremeAngY, extremeAngY, 0.1,0.5,"max y limit"); - + uiDefButBitS(block, TOG, 16, B_CONSTRAINT_TEST, "AngMaxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum y limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[4]), -extremeAngY, extremeAngY, 0.1,0.5,"max y limit"); + uiBlockEndAlign(block); + offsetY += 20; uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 32, B_CONSTRAINT_TEST, "AngMinZ", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[5]), -extremeAngZ, extremeAngZ, 0.1,0.5,"min z limit"); - + uiDefButBitS(block, TOG, 32, B_CONSTRAINT_TEST, "AngMinZ", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[5]), -extremeAngZ, extremeAngZ, 0.1,0.5,"min z limit"); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, 32, B_CONSTRAINT_TEST, "AngMaxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum z limit"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[5]), -extremeAngZ, extremeAngZ, 0.1,0.5,"max z limit"); + uiDefButBitS(block, TOG, 32, B_CONSTRAINT_TEST, "AngMaxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum z limit"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[5]), -extremeAngZ, extremeAngZ, 0.1,0.5,"max z limit"); uiBlockEndAlign(block); } } @@ -1419,17 +1390,17 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* Draw XYZ toggles */ uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Main Axis:", *xco, *yco-64, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Auto", *xco+100, *yco-64, 50, 18, &data->flag, 12.0, CLAMPTO_AUTO, 0, 0, "Automatically determine main-axis of movement"); - uiDefButI(block, ROW, B_CONSTRAINT_TEST, "X", *xco+150, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_X, 0, 0, "Main axis of movement is x-axis"); - uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Y", *xco+182, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_Y, 0, 0, "Main axis of movement is y-axis"); - uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Z", *xco+214, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_Z, 0, 0, "Main axis of movement is z-axis"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Main Axis:", *xco, *yco-64, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Auto", *xco+100, *yco-64, 50, 18, &data->flag, 12.0, CLAMPTO_AUTO, 0, 0, "Automatically determine main-axis of movement"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST, "X", *xco+150, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_X, 0, 0, "Main axis of movement is x-axis"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Y", *xco+182, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_Y, 0, 0, "Main axis of movement is y-axis"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Z", *xco+214, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_Z, 0, 0, "Main axis of movement is z-axis"); uiBlockEndAlign(block); /* Extra Options Controlling Behaviour */ uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Options:", *xco, *yco-86, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - uiDefButBitI(block, TOG, CLAMPTO_CYCLIC, B_CONSTRAINT_TEST, "Cyclic", *xco+((width/2)), *yco-86,60,19, &data->flag2, 0, 0, 0, 0, "Treat curve as cyclic curve (no clamping to curve bounding box)"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Options:", *xco, *yco-86, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButBitI(block, TOG, CLAMPTO_CYCLIC, B_CONSTRAINT_TEST, "Cyclic", *xco+((width/2)), *yco-86,60,19, &data->flag2, 0, 0, 0, 0, "Treat curve as cyclic curve (no clamping to curve bounding box)"); uiBlockEndAlign(block); } break; @@ -1446,20 +1417,19 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* Draw target parameters */ uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object to use as Parent"); - - if (is_armature_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone to use as Parent"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); - } - else if (is_geom_target) { - but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-66,150,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); - } - else { - strcpy(data->subtarget, ""); - } - + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object to use as Parent"); + + if (is_armature_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone to use as Parent"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-66,150,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } uiBlockEndAlign(block); /* Extrapolate Ranges? */ @@ -1470,9 +1440,9 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* draw Loc/Rot/Size toggles */ uiBlockBeginAlign(block); - uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Loc", *xco-5, *yco-82, 45, 18, &data->from, 12.0, 0, 0, 0, "Use Location transform channels from Target"); - uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Rot", *xco+40, *yco-82, 45, 18, &data->from, 12.0, 1, 0, 0, "Use Rotation transform channels from Target"); - uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Scale", *xco+85, *yco-82, 45, 18, &data->from, 12.0, 2, 0, 0, "Use Scale transform channels from Target"); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Loc", *xco-5, *yco-82, 45, 18, &data->from, 12.0, 0, 0, 0, "Use Location transform channels from Target"); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Rot", *xco+40, *yco-82, 45, 18, &data->from, 12.0, 1, 0, 0, "Use Rotation transform channels from Target"); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Scale", *xco+85, *yco-82, 45, 18, &data->from, 12.0, 2, 0, 0, "Use Scale transform channels from Target"); uiBlockEndAlign(block); /* Draw Pairs of Axis: Min/Max Value*/ @@ -1490,21 +1460,21 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s } uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "X:", *xco-10, *yco-107, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-107, 55, 18, &data->from_min[0], fmin, fmax, 0, 0, "Bottom of range of x-axis source motion for source->target mapping"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-107, 55, 18, &data->from_max[0], fmin, fmax, 0, 0, "Top of range of x-axis source motion for source->target mapping"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "X:", *xco-10, *yco-107, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-107, 55, 18, &data->from_min[0], fmin, fmax, 0, 0, "Bottom of range of x-axis source motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-107, 55, 18, &data->from_max[0], fmin, fmax, 0, 0, "Top of range of x-axis source motion for source->target mapping"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Y:", *xco-10, *yco-127, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-127, 55, 18, &data->from_min[1], fmin, fmax, 0, 0, "Bottom of range of y-axis source motion for source->target mapping"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-127, 55, 18, &data->from_max[1], fmin, fmax, 0, 0, "Top of range of y-axis source motion for source->target mapping"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Y:", *xco-10, *yco-127, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-127, 55, 18, &data->from_min[1], fmin, fmax, 0, 0, "Bottom of range of y-axis source motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-127, 55, 18, &data->from_max[1], fmin, fmax, 0, 0, "Top of range of y-axis source motion for source->target mapping"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Z:", *xco-10, *yco-147, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-147, 55, 18, &data->from_min[2], fmin, fmax, 0, 0, "Bottom of range of z-axis source motion for source->target mapping"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-147, 55, 18, &data->from_max[2], fmin, fmax, 0, 0, "Top of range of z-axis source motion for source->target mapping"); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Z:", *xco-10, *yco-147, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-147, 55, 18, &data->from_min[2], fmin, fmax, 0, 0, "Bottom of range of z-axis source motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-147, 55, 18, &data->from_max[2], fmin, fmax, 0, 0, "Top of range of z-axis source motion for source->target mapping"); uiBlockEndAlign(block); @@ -1513,9 +1483,9 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s /* draw Loc/Rot/Size toggles */ uiBlockBeginAlign(block); - uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Loc", *xco+150, *yco-82, 45, 18, &data->to, 12.0, 0, 0, 0, "Use as Location transform"); - uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Rot", *xco+195, *yco-82, 45, 18, &data->to, 12.0, 1, 0, 0, "Use as Rotation transform"); - uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Scale", *xco+245, *yco-82, 45, 18, &data->to, 12.0, 2, 0, 0, "Use as Scale transform"); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Loc", *xco+150, *yco-82, 45, 18, &data->to, 12.0, 0, 0, 0, "Use as Location transform"); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Rot", *xco+195, *yco-82, 45, 18, &data->to, 12.0, 1, 0, 0, "Use as Rotation transform"); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Scale", *xco+245, *yco-82, 45, 18, &data->to, 12.0, 2, 0, 0, "Use as Scale transform"); uiBlockEndAlign(block); /* Draw Pairs of Source-Axis: Min/Max Value*/ @@ -1533,25 +1503,25 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s } uiBlockBeginAlign(block); - uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->X%x0|Y->X%x1|Z->X%x2", *xco+150, *yco-107, 40, 18, &data->map[0], 0, 24, 0, 0, "Specify which source axis the x-axis destination uses"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-107, 50, 18, &data->to_min[0], tmin, tmax, 0, 0, "Bottom of range of x-axis destination motion for source->target mapping"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-107, 50, 18, &data->to_max[0], tmin, tmax, 0, 0, "Top of range of x-axis destination motion for source->target mapping"); + uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->X%x0|Y->X%x1|Z->X%x2", *xco+150, *yco-107, 40, 18, &data->map[0], 0, 24, 0, 0, "Specify which source axis the x-axis destination uses"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-107, 50, 18, &data->to_min[0], tmin, tmax, 0, 0, "Bottom of range of x-axis destination motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-107, 50, 18, &data->to_max[0], tmin, tmax, 0, 0, "Top of range of x-axis destination motion for source->target mapping"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->Y%x0|Y->Y%x1|Z->Y%x2", *xco+150, *yco-127, 40, 18, &data->map[1], 0, 24, 0, 0, "Specify which source axis the y-axis destination uses"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-127, 50, 18, &data->to_min[1], tmin, tmax, 0, 0, "Bottom of range of y-axis destination motion for source->target mapping"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-127, 50, 18, &data->to_max[1], tmin, tmax, 0, 0, "Top of range of y-axis destination motion for source->target mapping"); + uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->Y%x0|Y->Y%x1|Z->Y%x2", *xco+150, *yco-127, 40, 18, &data->map[1], 0, 24, 0, 0, "Specify which source axis the y-axis destination uses"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-127, 50, 18, &data->to_min[1], tmin, tmax, 0, 0, "Bottom of range of y-axis destination motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-127, 50, 18, &data->to_max[1], tmin, tmax, 0, 0, "Top of range of y-axis destination motion for source->target mapping"); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->Z%x0|Y->Z%x1|Z->Z%x2", *xco+150, *yco-147, 40, 18, &data->map[2], 0, 24, 0, 0, "Specify which source axis the z-axis destination uses"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-147, 50, 18, &data->to_min[2], tmin, tmax, 0, 0, "Bottom of range of z-axis destination motion for source->target mapping"); - uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-147, 50, 18, &data->to_max[2], tmin, tmax, 0, 0, "Top of range of z-axis destination motion for source->target mapping"); + uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->Z%x0|Y->Z%x1|Z->Z%x2", *xco+150, *yco-147, 40, 18, &data->map[2], 0, 24, 0, 0, "Specify which source axis the z-axis destination uses"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-147, 50, 18, &data->to_min[2], tmin, tmax, 0, 0, "Bottom of range of z-axis destination motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-147, 50, 18, &data->to_max[2], tmin, tmax, 0, 0, "Top of range of z-axis destination motion for source->target mapping"); uiBlockEndAlign(block); /* constraint space settings */ - draw_constraint_spaceselect(block, con, *xco, *yco-170, is_armature_owner, is_armature_target); + draw_constraint_spaceselect(block, con, *xco, *yco-170, is_armature_owner(ob), is_armature_target(data->tar)); } break; case CONSTRAINT_TYPE_NULL: @@ -1564,11 +1534,11 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s height = 0; break; } - + (*yco)-=(24+height); } - if ((con->type != CONSTRAINT_TYPE_NULL) && (con->type!=CONSTRAINT_TYPE_RIGIDBODYJOINT)) { + if (ELEM(con->type, CONSTRAINT_TYPE_NULL, CONSTRAINT_TYPE_RIGIDBODYJOINT)==0) { uiBlockBeginAlign(block); uiDefButF(block, NUMSLI, B_CONSTRAINT_INF, "Influence ", *xco, *yco, 197, 20, &(con->enforce), 0.0, 1.0, 0.0, 0.0, "Amount of influence this constraint will have on the final solution"); but = uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Show", *xco+200, *yco, 45, 20, 0, 0.0, 1.0, 0.0, 0.0, "Show constraint's ipo in the Ipo window, adds a channel if not there"); diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c index f637734fa34..b65a34c9972 100644 --- a/source/blender/src/drawobject.c +++ b/source/blender/src/drawobject.c @@ -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); } } diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 81467b95297..2e7da10d8ca 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -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); } } } diff --git a/source/blender/src/editconstraint.c b/source/blender/src/editconstraint.c index 5da083ee9a2..c0bc964c07a 100644 --- a/source/blender/src/editconstraint.c +++ b/source/blender/src/editconstraint.c @@ -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); diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index 593d9ecdcdc..1c9cf15bc7e 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -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]; diff --git a/source/blender/src/header_text.c b/source/blender/src/header_text.c index 32268c35210..04c354fb2b1 100644 --- a/source/blender/src/header_text.c +++ b/source/blender/src/header_text.c @@ -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); } } } diff --git a/source/blender/src/outliner.c b/source/blender/src/outliner.c index 37d25e4f100..0ed50c75ad4 100644 --- a/source/blender/src/outliner.c +++ b/source/blender/src/outliner.c @@ -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? */ } diff --git a/source/blender/src/poseobject.c b/source/blender/src/poseobject.c index 5e78abd8b41..faae6bd0da4 100644 --- a/source/blender/src/poseobject.c +++ b/source/blender/src/poseobject.c @@ -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); } } }