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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2007-10-22 03:00:29 +0400
committerJoshua Leung <aligorith@gmail.com>2007-10-22 03:00:29 +0400
commit6422a740c25d33c7e7dcc008d215ae983be00a30 (patch)
treedddeca774208da69659dfbc6f75616dcc6deadd7 /source/blender
parenta4e8e87983829e05d33b2c5aa39f88ca24d48cdd (diff)
== Constraints System - Recode 2 ==
Once again, I've recoded the constraints system. This time, the goals were: * To make it more future-proof by 'modernising' the coding style. The long functions filled with switch statements, have given way to function-pointers with smaller functions for specific purposes. * To make it support constraints which use multiple targets more readily that it did. In the past, it was assumed that constraints could only have at most one target. As a result, a lot of code has been shuffled around, and modified. Also, the subversion number has been bumped up. Known issues: * PyConstraints, which were the main motivation for supporting multiple-targets, are currently broken. There are some bimport() error that keeps causing problems. I've also temporarily removed the doDriver support, although it may return in another form soon. * Constraints BPy-API is currently has a few features which currently don't work yet * Outliner currently only displays the names of the constraints instead of the fancy subtarget/target/constraint-name display it used to do. What gets displayed here needs further investigation, as the old way was certainly not that great (and is not compatible with the new system too)
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_bad_level_calls.h7
-rw-r--r--source/blender/blenkernel/BKE_blender.h2
-rw-r--r--source/blender/blenkernel/BKE_constraint.h87
-rw-r--r--source/blender/blenkernel/bad_level_call_stubs/stubs.c10
-rw-r--r--source/blender/blenkernel/intern/armature.c50
-rw-r--r--source/blender/blenkernel/intern/constraint.c4573
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c165
-rw-r--r--source/blender/blenkernel/intern/object.c69
-rw-r--r--source/blender/blenloader/intern/readfile.c93
-rw-r--r--source/blender/blenloader/intern/writefile.c89
-rw-r--r--source/blender/include/BIF_editconstraint.h3
-rw-r--r--source/blender/include/butspace.h1
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h168
-rw-r--r--source/blender/python/BPY_extern.h10
-rw-r--r--source/blender/python/BPY_interface.c535
-rw-r--r--source/blender/python/api2_2x/Constraint.c71
-rw-r--r--source/blender/src/buttons_object.c956
-rw-r--r--source/blender/src/drawobject.c53
-rw-r--r--source/blender/src/editarmature.c57
-rw-r--r--source/blender/src/editconstraint.c192
-rw-r--r--source/blender/src/editobject.c19
-rw-r--r--source/blender/src/header_text.c20
-rw-r--r--source/blender/src/outliner.c6
-rw-r--r--source/blender/src/poseobject.c33
24 files changed, 4038 insertions, 3231 deletions
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 */
/* ---------------------------------------------------------------------------- */
@@ -65,26 +55,77 @@ typedef struct 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);
+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(ListBase *chanbase);
+void free_constraint_channels(struct 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 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)
-{
- 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) {
- con->data = MEM_dupallocN (con->data);
-
- /* only do specific constraints if required */
- if (con->type == CONSTRAINT_TYPE_PYTHON) {
- bPythonConstraint *pycon = (bPythonConstraint *)con->data;
- bPythonConstraint *opycon = (bPythonConstraint *)srccon->data;
-
- pycon->prop = IDP_CopyProperty(opycon->prop);
- }
- }
-}
-
-/* **************** Editor Functions **************** */
+/* ------------- Constraint Channel Tools ------------ */
-char constraint_has_target (bConstraint *con)
+/* Find the constraint channel with a given name */
+bConstraintChannel *get_constraint_channel (ListBase *list, const char name[])
{
- 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;
+ bConstraintChannel *chan;
+
+ for (chan = list->first; chan; chan=chan->next) {
+ if (!strcmp(name, chan->name)) {
+ return chan;
}
- break;
}
- /* Unknown types or CONSTRAINT_TYPE_NULL or no target */
- return 0;
+ return NULL;
}
-Object *get_constraint_target(bConstraint *con, char **subtarget)
+/* Find or create a new constraint channel */
+bConstraintChannel *verify_constraint_channel (ListBase *list, const char name[])
{
- /* 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;
+ bConstraintChannel *chan;
+
+ 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 NULL;
+ return chan;
}
-void set_constraint_target(bConstraint *con, Object *ob, char *subtarget)
+/* --------- 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)
{
- /* 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);
+ 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;
+ }
+ }
+ }
}
- break;
}
}
+/* ************************ 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.
+ */
+
+/* -------------- 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;
+ 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);
+ }
+}
- 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;
+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 */
+};
+
+/* --------- Inverse-Kinemetics --------- */
+
+static void kinematic_new_data (void *cdata)
+{
+ 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;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data, ct, list)
+ }
+}
+
+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 (ob == NULL) {
+ Mat4One(ct->matrix);
}
- 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 {
+ 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);
}
- 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;
+ else
+ Mat4One(ct->matrix);
+ }
+}
+
+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) {
- constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace);
- valid=1;
+ if (calc_ipo_spec(cu->ipo, CU_SPEED, &curvetime)==0) {
+ curvetime /= cu->pathlen;
+ CLAMP(curvetime, 0.0, 1.0);
}
- 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 ( where_on_path(ct->tar, curvetime, vec, dir) ) {
+ if (data->followflag) {
+ quat= vectoquat(dir, (short) data->trackflag, (short) data->upflag);
- if (calc_ipo_spec(cu->ipo, CU_SPEED, &curvetime)==0) {
- curvetime /= cu->pathlen;
- CLAMP(curvetime, 0.0, 1.0);
- }
+ 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);
- 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);
- }
+ QuatToMat4(quat, totmat);
}
- valid=1;
+ VECCOPY(totmat[3], vec);
+
+ Mat4MulSerie(ct->matrix, ct->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL);
}
- else
- Mat4One(mat);
}
- break;
- case CONSTRAINT_TYPE_STRETCHTO:
- {
- bStretchToConstraint *data;
- data = (bStretchToConstraint*)con->data;
+ }
+ else if (ct)
+ Mat4One(ct->matrix);
+}
+
+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 (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;
+ if (eul[0] > data->xmax)
+ eul[0] = data->xmax;
+ }
+ if (data->flag & LIMIT_YROT) {
+ if (eul[1] < data->ymin)
+ eul[1] = data->ymin;
- /* 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 (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];
- /* 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;
+ 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);
}
- if (!valid)
- Mat4One(mat);
+ 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);
}
- break;
- case CONSTRAINT_TYPE_CLAMPTO:
- {
- bClampToConstraint *data;
- data = (bClampToConstraint*)con->data;
+ 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->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;
- }
+ if (data->flag & LOCLIKE_X) {
+ cob->matrix[3][0] = ct->matrix[3][0];
- Mat4One(mat);
+ if (data->flag & LOCLIKE_X_INVERT) cob->matrix[3][0] *= -1;
+ cob->matrix[3][0] += offset[0];
}
- break;
- case CONSTRAINT_TYPE_CHILDOF:
- {
- bChildOfConstraint *data;
- data= (bChildOfConstraint *)con->data;
+ if (data->flag & LOCLIKE_Y) {
+ cob->matrix[3][1] = ct->matrix[3][1];
- if (data->tar) {
- constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace);
- valid = 1;
- }
- else
- Mat4One(mat);
+ if (data->flag & LOCLIKE_Y_INVERT) cob->matrix[3][1] *= -1;
+ cob->matrix[3][1] += offset[1];
}
- break;
- case CONSTRAINT_TYPE_TRANSFORM:
- {
- bTransformConstraint *data;
- data= (bTransformConstraint *)con->data;
+ if (data->flag & LOCLIKE_Z) {
+ cob->matrix[3][2] = ct->matrix[3][2];
- if (data->tar) {
- constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace);
- valid = 1;
- }
- else
- Mat4One(mat);
+ if (data->flag & LOCLIKE_Z_INVERT) cob->matrix[3][2] *= -1;
+ cob->matrix[3][2] += offset[2];
}
- break;
-
- default:
- Mat4One(mat);
- break;
}
+}
- return valid;
+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;
}
-/* ---------------------------------------------- Constraint Evaluation ------------------------------------------------- */
+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)
+ }
+}
-/* 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])
+static void rotlike_flush_tars (bConstraint *con, ListBase *list, short nocopy)
{
- if (constraint == NULL || constraint->data == NULL)
- return;
+ if (con && list) {
+ bRotateLikeConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
- 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);
+ /* 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];
}
- break;
- case CONSTRAINT_TYPE_LOCLIKE:
- {
- bLocateLikeConstraint *data;
- float offset[3] = {0.0f, 0.0f, 0.0f};
+ 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);
+ }
+}
- data = constraint->data;
-
- if (data->flag & LOCLIKE_OFFSET)
- VECCOPY(offset, ownermat[3]);
+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;
- 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 (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];
- }
+ /* 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);
}
- 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);
+
+ /* 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;
}
- 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:
+
+ /* 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 */
{
- 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;
- }
+ 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]);
}
- if (data->flag & MINMAX_USEROT) {
- /* get out of localspace */
- Mat4MulMat4(tmat, obmat, targetmat);
- Mat4CpyMat4(ownermat, tmat);
- }
- else {
- VECCOPY(ownermat[3], obmat[3]);
+ break;
+ case TRACK_Z: /* LOCK X TRACK Z */
+ {
+ /* 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]);
}
- }
- else {
- data->flag &= ~MINMAX_STUCK;
+ 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;
}
}
- break;
- case CONSTRAINT_TYPE_TRACKTO:
+ break;
+ case LOCK_Y: /* LOCK Y */
{
- bTrackToConstraint *data;
- float size[3], vec[3];
- float totmat[3][3];
- float tmat[4][4];
-
- data = constraint->data;
-
- 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);
+ 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]);
+
+ /* 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;
+ 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);
+
+ /* 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_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 CONSTRAINT_TYPE_LOCKTRACK:
+ break;
+ case LOCK_Z: /* LOCK Z */
{
- 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_X: /* LOCK Z TRACK 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]);
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[2]);
+ VecSubf(totmat[0], vec, vec2);
+ 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, 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;
- }
+ /* 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 LOCK_Y: /* LOCK Y */
+ case TRACK_Y: /* LOCK Z TRACK 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]);
-
- /* 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;
- }
+ /* 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]);
+
+ /* the x axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[0], totmat[1], totmat[2]);
}
break;
- case LOCK_Z: /* LOCK Z */
+ case TRACK_nX: /* LOCK Z TRACK -X */
{
- 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[2]);
+ VecSubf(totmat[0], vec, vec2);
+ Normalize(totmat[0]);
+ VecMulf(totmat[0],-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]);
+
+ /* 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, 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]);
+
+ /* 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;
}
- /* 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:
- {
- 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;
+ 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 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];
-
- 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;
+ /* 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);
+ }
+}
- 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;
- }
+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);
}
- 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;
-
- 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);
+
+ 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;
}
- 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 (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 & LIMIT_ZMAX) {
- if (size[2] > data->zmax)
- size[2] = data->zmax;
+ 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]);
}
-
- VecMulf(ownermat[0], size[0]/obsize[0]);
- VecMulf(ownermat[1], size[1]/obsize[1]);
- VecMulf(ownermat[2], size[2]/obsize[2]);
+ }
+ else {
+ data->flag &= ~MINMAX_STUCK;
}
- 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;
+ }
+}
+
+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 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];
- /* 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;
+ while (ownLoc[clamp_axis] < offset)
+ offset -= len;
- /* 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;
+ /* 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];
- /* 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);
+ 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 {
- /* 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);
-
- Mat4MulSerie(targetMatrix, data->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL);
+ /* 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]);
+ }
- /* 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);
+ /* 3. position on curve */
+ if (where_on_path(ct->tar, curvetime, vec, dir) ) {
+ Mat4One(totmat);
+ VECCOPY(totmat[3], vec);
- /* 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);
+ Mat4MulSerie(targetMatrix, ct->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL);
}
}
- 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;
+
+ /* 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};
- /* extract components of owner's matrix */
- VECCOPY(loc, ownermat[3]);
- Mat4ToEul(ownermat, eul);
- Mat4ToSize(ownermat, size);
+ cti->get_constraint_targets(con, &targets);
+ for (ct= targets.first; ct; ct= ct->next) {
+ ID_NEW(ct->tar);
+ }
- /* 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;
- }
+ 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 {
- /* 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;
+ Mat4One(cob->matrix);
+ Mat4One(cob->startmat);
}
- 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;
+ }
+ 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);
}
-
- /* 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, ownermat[3], loc);
- break;
+ else {
+ Mat4One(cob->matrix);
+ Mat4One(cob->startmat);
}
-
- /* apply to matrix */
- LocEulSizeToMat4(ownermat, loc, eul, size);
}
+ break;
}
- break;
- default:
- printf("Error: Unknown constraint type\n");
- 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 */
+/* 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;
+
+ /* 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);
- /* as usual, the function for this is defined in BPY_interface.c */
- BPY_pyconstraint_driver(pycon, cob, pycon->tar, pycon->subtarget);
+ /* 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 ) {
+
+ 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( 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);
- Py_XDECREF( tar );
- Py_XDECREF( subtar );
- Py_XDECREF( idprop );
- Py_XDECREF( tarmat );
- return -1;
+ 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);
- }
- 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, "");
+ 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);
}
-
- 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");
-
+ 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);
- uiDefButS(block, NUM, B_CONSTRAINT_TEST, "Iterations:", *xco, *yco-109, 137, 19, &data->iterations, 1, 10000, 0, 0, "Maximum number of solving iterations");
+ 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);
- 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");
+ 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");
+ 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, "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);
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");
+ 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");
+ 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,"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);
}
}
}