Constraints API: ID-Loopers
authorJoshua Leung <aligorith@gmail.com>
Sat, 6 Feb 2010 11:28:22 +0000 (11:28 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sat, 6 Feb 2010 11:28:22 +0000 (11:28 +0000)
Added a system for running a callback on all the ID-blocks referenced by constraints (like for modifiers). Also, added an API function which calls these on the constraints present in the given list.

These could be used for:
- the proxies + action/pyconstraint fix that campbell committed
- simplification of file loading code

source/blender/blenkernel/BKE_constraint.h
source/blender/blenkernel/intern/constraint.c

index e9110b99098a94c7b3c9eb2b01b937a35b381429..840b4cef85a4321c86147add6830169433cb4516 100644 (file)
@@ -30,6 +30,7 @@
 #ifndef BKE_CONSTRAINT_H
 #define BKE_CONSTRAINT_H
 
+struct ID;
 struct bConstraint;
 struct bConstraintTarget;
 struct ListBase;
@@ -57,6 +58,11 @@ typedef struct bConstraintOb {
 
 /* ---------------------------------------------------------------------------- */
 
+/* Callback format for performing operations on ID-pointers for Constraints */
+typedef void (*ConstraintIDFunc)(struct bConstraint *con, struct ID **idpoin, void *userdata);
+
+/* ....... */
+
 /* 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).
@@ -80,6 +86,8 @@ typedef struct bConstraintTypeInfo {
        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);
+               /* run the provided callback function on all the ID-blocks linked to the constraint */
+       void (*id_looper)(struct bConstraint *con, ConstraintIDFunc func, void *userdata);
                /* 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 using MEM_callocN) */
@@ -116,6 +124,7 @@ void unique_constraint_name(struct bConstraint *con, struct ListBase *list);
 void free_constraints(struct ListBase *list);
 void copy_constraints(struct ListBase *dst, const struct ListBase *src);
 void relink_constraints(struct ListBase *list);
+void id_loop_constraints(struct ListBase *list, ConstraintIDFunc func, void *userdata);
 void free_constraint_data(struct bConstraint *con);
 
 /* Constraint API function prototypes */
index 9624346f9e2d79d6ce4bd75cea4c53c3239954d5..18bf824f8d3944928cc247a70e97a88b016a17a4 100644 (file)
@@ -648,6 +648,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
        "bConstrNameConstraint", /* struct name */
        constrname_free, /* free data */
        constrname_relink, /* relink data */
+       constrname_id_looper, /* id looper */
        constrname_copy, /* copy data */
        constrname_new_data, /* new data */
        constrname_get_tars, /* get constraint targets */
@@ -774,6 +775,14 @@ static void childof_new_data (void *cdata)
        unit_m4(data->invmat);
 }
 
+static void childof_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bChildOfConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int childof_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -858,6 +867,7 @@ static bConstraintTypeInfo CTI_CHILDOF = {
        "bChildOfConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       childof_id_looper, /* id looper */
        NULL, /* copy data */
        childof_new_data, /* new data */
        childof_get_tars, /* get constraint targets */
@@ -876,6 +886,14 @@ static void trackto_new_data (void *cdata)
        data->reserved2 = UP_Z;
 }      
 
+static void trackto_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bTrackToConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int trackto_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -1037,6 +1055,7 @@ static bConstraintTypeInfo CTI_TRACKTO = {
        "bTrackToConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       trackto_id_looper, /* id looper */
        NULL, /* copy data */
        trackto_new_data, /* new data */
        trackto_get_tars, /* get constraint targets */
@@ -1058,6 +1077,17 @@ static void kinematic_new_data (void *cdata)
        data->flag= CONSTRAINT_IK_TIP|CONSTRAINT_IK_STRETCH|CONSTRAINT_IK_POS;
 }
 
+static void kinematic_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bKinematicConstraint *data= con->data;
+       
+       /* chain target */
+       func(con, (ID**)&data->tar, userdata);
+       
+       /* poletarget */
+       func(con, (ID**)&data->poletar, userdata);
+}
+
 static int kinematic_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -1120,6 +1150,7 @@ static bConstraintTypeInfo CTI_KINEMATIC = {
        "bKinematicConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       kinematic_id_looper, /* id looper */
        NULL, /* copy data */
        kinematic_new_data, /* new data */
        kinematic_get_tars, /* get constraint targets */
@@ -1140,6 +1171,14 @@ static void followpath_new_data (void *cdata)
        data->followflag = 0;
 }
 
+static void followpath_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bFollowPathConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int followpath_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -1283,6 +1322,7 @@ static bConstraintTypeInfo CTI_FOLLOWPATH = {
        "bFollowPathConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       followpath_id_looper, /* id looper */
        NULL, /* copy data */
        followpath_new_data, /* new data */
        followpath_get_tars, /* get constraint targets */
@@ -1331,6 +1371,7 @@ static bConstraintTypeInfo CTI_LOCLIMIT = {
        "bLocLimitConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       NULL, /* id looper */
        NULL, /* copy data */
        NULL, /* new data */
        NULL, /* get constraint targets */
@@ -1388,6 +1429,7 @@ static bConstraintTypeInfo CTI_ROTLIMIT = {
        "bRotLimitConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       NULL, /* id looper */
        NULL, /* copy data */
        NULL, /* new data */
        NULL, /* get constraint targets */
@@ -1447,6 +1489,7 @@ static bConstraintTypeInfo CTI_SIZELIMIT = {
        "bSizeLimitConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       NULL, /* id looper */
        NULL, /* copy data */
        NULL, /* new data */
        NULL, /* get constraint targets */
@@ -1464,6 +1507,14 @@ static void loclike_new_data (void *cdata)
        data->flag = LOCLIKE_X|LOCLIKE_Y|LOCLIKE_Z;
 }
 
+static void loclike_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bLocateLikeConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int loclike_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -1529,6 +1580,7 @@ static bConstraintTypeInfo CTI_LOCLIKE = {
        "bLocateLikeConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       loclike_id_looper, /* id looper */
        NULL, /* copy data */
        loclike_new_data, /* new data */
        loclike_get_tars, /* get constraint targets */
@@ -1546,6 +1598,14 @@ static void rotlike_new_data (void *cdata)
        data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z;
 }
 
+static void rotlike_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bChildOfConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int rotlike_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -1631,6 +1691,7 @@ static bConstraintTypeInfo CTI_ROTLIKE = {
        "bRotateLikeConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       rotlike_id_looper, /* id looper */
        NULL, /* copy data */
        rotlike_new_data, /* new data */
        rotlike_get_tars, /* get constraint targets */
@@ -1648,6 +1709,14 @@ static void sizelike_new_data (void *cdata)
        data->flag = SIZELIKE_X|SIZELIKE_Y|SIZELIKE_Z;
 }
 
+static void sizelike_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bSizeLikeConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int sizelike_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -1719,6 +1788,7 @@ static bConstraintTypeInfo CTI_SIZELIKE = {
        "bSizeLikeConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       sizelike_id_looper, /* id looper */
        NULL, /* copy data */
        sizelike_new_data, /* new data */
        sizelike_get_tars, /* get constraint targets */
@@ -1729,6 +1799,14 @@ static bConstraintTypeInfo CTI_SIZELIKE = {
 
 /* ----------- Copy Transforms ------------- */
 
+static void translike_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bTransLikeConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int translike_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -1772,6 +1850,7 @@ static bConstraintTypeInfo CTI_TRANSLIKE = {
        "bTransLikeConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       translike_id_looper, /* id looper */
        NULL, /* copy data */
        NULL, /* new data */
        translike_get_tars, /* get constraint targets */
@@ -1833,6 +1912,19 @@ static int pycon_get_tars (bConstraint *con, ListBase *list)
        return 0;
 }
 
+static void pycon_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bPythonConstraint *data= con->data;
+       bConstraintTarget *ct;
+       
+       /* targets */
+       for (ct= data->targets.first; ct; ct= ct->next)
+               func(con, (ID**)&ct->tar, userdata);
+               
+       /* script */
+       func(con, (ID**)&data->text, userdata);
+}
+
 /* Whether this approach is maintained remains to be seen (aligorith) */
 static void pycon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime)
 {
@@ -1894,6 +1986,7 @@ static bConstraintTypeInfo CTI_PYTHON = {
        "bPythonConstraint", /* struct name */
        pycon_free, /* free data */
        pycon_relink, /* relink data */
+       pycon_id_looper, /* id looper */
        pycon_copy, /* copy data */
        pycon_new_data, /* new data */
        pycon_get_tars, /* get constraint targets */
@@ -1921,11 +2014,22 @@ static void actcon_new_data (void *cdata)
 /* only for setting the ID as extern */
 static void actcon_copy_data (bConstraint *con, bConstraint *srccon)
 {
-       bActionConstraint *src= srccon->data;
+       //bActionConstraint *src= srccon->data;
        bActionConstraint *dst= con->data;
        id_lib_extern((ID *)dst->act); /* would be better solved with something like modifiers_foreachIDLink */
 }
 
+static void actcon_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bActionConstraint *data= con->data;
+       
+       /* target */
+       func(con, (ID**)&data->tar, userdata);
+       
+       /* action */
+       func(con, (ID**)&data->act, userdata);
+}
+
 static int actcon_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -2065,6 +2169,7 @@ static bConstraintTypeInfo CTI_ACTION = {
        "bActionConstraint", /* struct name */
        NULL, /* free data */
        actcon_relink, /* relink data */
+       actcon_id_looper, /* id looper */
        actcon_copy_data, /* copy data */
        actcon_new_data, /* new data */
        actcon_get_tars, /* get constraint targets */
@@ -2083,6 +2188,14 @@ static void locktrack_new_data (void *cdata)
        data->lockflag = LOCK_Z;
 }      
 
+static void locktrack_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bLockTrackConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int locktrack_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -2418,6 +2531,7 @@ static bConstraintTypeInfo CTI_LOCKTRACK = {
        "bLockTrackConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       locktrack_id_looper, /* id looper */
        NULL, /* copy data */
        locktrack_new_data, /* new data */
        locktrack_get_tars, /* get constraint targets */
@@ -2432,7 +2546,15 @@ static void distlimit_new_data (void *cdata)
 {
        bDistLimitConstraint *data= (bDistLimitConstraint *)cdata;
        
-       data->dist= 0.0;
+       data->dist= 0.0f;
+}
+
+static void distlimit_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bDistLimitConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
 }
 
 static int distlimit_get_tars (bConstraint *con, ListBase *list)
@@ -2534,6 +2656,7 @@ static bConstraintTypeInfo CTI_DISTLIMIT = {
        "bDistLimitConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       distlimit_id_looper, /* id looper */
        NULL, /* copy data */
        distlimit_new_data, /* new data */
        distlimit_get_tars, /* get constraint targets */
@@ -2554,6 +2677,14 @@ static void stretchto_new_data (void *cdata)
        data->bulge = 1.0;
 }
 
+static void stretchto_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bStretchToConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int stretchto_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -2714,6 +2845,7 @@ static bConstraintTypeInfo CTI_STRETCHTO = {
        "bStretchToConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       stretchto_id_looper, /* id looper */
        NULL, /* copy data */
        stretchto_new_data, /* new data */
        stretchto_get_tars, /* get constraint targets */
@@ -2734,6 +2866,14 @@ static void minmax_new_data (void *cdata)
        data->flag = 0;
 }
 
+static void minmax_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bMinMaxConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int minmax_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -2850,6 +2990,7 @@ static bConstraintTypeInfo CTI_MINMAX = {
        "bMinMaxConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       minmax_id_looper, /* id looper */
        NULL, /* copy data */
        minmax_new_data, /* new data */
        minmax_get_tars, /* get constraint targets */
@@ -2868,6 +3009,14 @@ static void rbj_new_data (void *cdata)
     data->type=1;
 }
 
+static void rbj_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bRigidBodyJointConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int rbj_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -2901,6 +3050,7 @@ static bConstraintTypeInfo CTI_RIGIDBODYJOINT = {
        "bRigidBodyJointConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       rbj_id_looper, /* id looper */
        NULL, /* copy data */
        rbj_new_data, /* new data */
        rbj_get_tars, /* get constraint targets */
@@ -2911,6 +3061,14 @@ static bConstraintTypeInfo CTI_RIGIDBODYJOINT = {
 
 /* -------- Clamp To ---------- */
 
+static void clampto_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bClampToConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int clampto_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -3078,6 +3236,7 @@ static bConstraintTypeInfo CTI_CLAMPTO = {
        "bClampToConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       clampto_id_looper, /* id looper */
        NULL, /* copy data */
        NULL, /* new data */
        clampto_get_tars, /* get constraint targets */
@@ -3097,6 +3256,14 @@ static void transform_new_data (void *cdata)
        data->map[2]= 2;
 }
 
+static void transform_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bTransformConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int transform_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -3217,6 +3384,7 @@ static bConstraintTypeInfo CTI_TRANSFORM = {
        "bTransformConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       transform_id_looper, /* id looper */
        NULL, /* copy data */
        transform_new_data, /* new data */
        transform_get_tars, /* get constraint targets */
@@ -3227,6 +3395,14 @@ static bConstraintTypeInfo CTI_TRANSFORM = {
 
 /* ---------- Shrinkwrap Constraint ----------- */
 
+static void shrinkwrap_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bShrinkwrapConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->target, userdata);
+}
+
 static int shrinkwrap_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -3374,6 +3550,7 @@ static bConstraintTypeInfo CTI_SHRINKWRAP = {
        "bShrinkwrapConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       shrinkwrap_id_looper, /* id looper */
        NULL, /* copy data */
        NULL, /* new data */
        shrinkwrap_get_tars, /* get constraint targets */
@@ -3391,6 +3568,14 @@ static void damptrack_new_data (void *cdata)
        data->trackflag = TRACK_Y;
 }      
 
+static void damptrack_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bDampTrackConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int damptrack_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -3493,6 +3678,7 @@ static bConstraintTypeInfo CTI_DAMPTRACK = {
        "bDampTrackConstraint", /* struct name */
        NULL, /* free data */
        NULL, /* relink data */
+       damptrack_id_looper, /* id looper */
        NULL, /* copy data */
        damptrack_new_data, /* new data */
        damptrack_get_tars, /* get constraint targets */
@@ -3521,6 +3707,14 @@ static void splineik_copy (bConstraint *con, bConstraint *srccon)
        dst->points= MEM_dupallocN(src->points);
 }
 
+static void splineik_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+       bSplineIKConstraint *data= con->data;
+       
+       /* target only */
+       func(con, (ID**)&data->tar, userdata);
+}
+
 static int splineik_get_tars (bConstraint *con, ListBase *list)
 {
        if (con && list) {
@@ -3575,6 +3769,7 @@ static bConstraintTypeInfo CTI_SPLINEIK = {
        "bSplineIKConstraint", /* struct name */
        splineik_free, /* free data */
        NULL, /* relink data */
+       splineik_id_looper, /* id looper */
        splineik_copy, /* copy data */
        NULL, /* new data */
        splineik_get_tars, /* get constraint targets */
@@ -3837,6 +4032,21 @@ void relink_constraints (ListBase *conlist)
        }
 }
 
+/* Run the given callback on all ID-blocks in list of constraints */
+void id_loop_constraints (ListBase *conlist, ConstraintIDFunc func, void *userdata)
+{
+       bConstraint *con;
+       
+       for (con= conlist->first; con; con= con->next) {
+               bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+               
+               if (cti) {
+                       if (cti->id_looper)
+                               cti->id_looper(con, func, userdata);
+               }
+       }
+}
+
 /* ......... */
 
 /* duplicate all of the constraints in a constraint stack */