Bugfixes for various ID-block references (Constraints, NLA)
authorJoshua Leung <aligorith@gmail.com>
Sat, 5 May 2012 15:54:08 +0000 (15:54 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sat, 5 May 2012 15:54:08 +0000 (15:54 +0000)
* ID-blocks referenced by Constraints but not being used as the target objects
(such as Actions in the Action Constraint, or Text Blocks in PyConstraints) now
get usercounts for being referenced in this way. This should fix ancient bugs
such as [#19205] and [#8593]. More tests still needed to verify that this
does now play nicely with proxies.

* Changing actions used by NLA strips should now update the usercounts
accordingly

source/blender/blenkernel/BKE_constraint.h
source/blender/blenkernel/intern/constraint.c
source/blender/blenloader/intern/readfile.c
source/blender/makesrna/intern/rna_animation.c
source/blender/makesrna/intern/rna_constraint.c
source/blender/makesrna/intern/rna_nla.c

index f834ad5e77409a3024ca39d891a35a0515b9c932..b12ab5381848175bdab1887d9e0133cf903f34b0 100644 (file)
@@ -62,7 +62,7 @@ typedef struct bConstraintOb {
 /* ---------------------------------------------------------------------------- */
 
 /* Callback format for performing operations on ID-pointers for Constraints */
-typedef void (*ConstraintIDFunc)(struct bConstraint *con, struct ID **idpoin, void *userdata);
+typedef void (*ConstraintIDFunc)(struct bConstraint *con, struct ID **idpoin, short isReference, void *userdata);
 
 /* ....... */
 
index 399aedc914fcebcb88a9c4ce5abd4cd1fac69db7..a244fa96fda390b0b7c9c7a79032b3f829b0ff5f 100644 (file)
@@ -781,7 +781,7 @@ static void childof_id_looper (bConstraint *con, ConstraintIDFunc func, void *us
        bChildOfConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int childof_get_tars (bConstraint *con, ListBase *list)
@@ -917,7 +917,7 @@ static void trackto_id_looper (bConstraint *con, ConstraintIDFunc func, void *us
        bTrackToConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int trackto_get_tars (bConstraint *con, ListBase *list)
@@ -1098,10 +1098,10 @@ static void kinematic_id_looper (bConstraint *con, ConstraintIDFunc func, void *
        bKinematicConstraint *data= con->data;
        
        /* chain target */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
        
        /* poletarget */
-       func(con, (ID**)&data->poletar, userdata);
+       func(con, (ID**)&data->poletar, FALSE, userdata);
 }
 
 static int kinematic_get_tars (bConstraint *con, ListBase *list)
@@ -1191,7 +1191,7 @@ static void followpath_id_looper (bConstraint *con, ConstraintIDFunc func, void
        bFollowPathConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int followpath_get_tars (bConstraint *con, ListBase *list)
@@ -1541,7 +1541,7 @@ static void loclike_id_looper (bConstraint *con, ConstraintIDFunc func, void *us
        bLocateLikeConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int loclike_get_tars (bConstraint *con, ListBase *list)
@@ -1632,7 +1632,7 @@ static void rotlike_id_looper (bConstraint *con, ConstraintIDFunc func, void *us
        bChildOfConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int rotlike_get_tars (bConstraint *con, ListBase *list)
@@ -1745,7 +1745,7 @@ static void sizelike_id_looper (bConstraint *con, ConstraintIDFunc func, void *u
        bSizeLikeConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int sizelike_get_tars (bConstraint *con, ListBase *list)
@@ -1835,7 +1835,7 @@ static void translike_id_looper (bConstraint *con, ConstraintIDFunc func, void *
        bTransLikeConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int translike_get_tars (bConstraint *con, ListBase *list)
@@ -2007,10 +2007,10 @@ static void pycon_id_looper (bConstraint *con, ConstraintIDFunc func, void *user
        
        /* targets */
        for (ct= data->targets.first; ct; ct= ct->next)
-               func(con, (ID**)&ct->tar, userdata);
+               func(con, (ID**)&ct->tar, FALSE, userdata);
                
        /* script */
-       func(con, (ID**)&data->text, userdata);
+       func(con, (ID**)&data->text, TRUE, userdata);
 }
 
 /* Whether this approach is maintained remains to be seen (aligorith) */
@@ -2107,10 +2107,10 @@ static void actcon_id_looper (bConstraint *con, ConstraintIDFunc func, void *use
        bActionConstraint *data= con->data;
        
        /* target */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
        
        /* action */
-       func(con, (ID**)&data->act, userdata);
+       func(con, (ID**)&data->act, TRUE, userdata);
 }
 
 static int actcon_get_tars (bConstraint *con, ListBase *list)
@@ -2273,7 +2273,7 @@ static void locktrack_id_looper (bConstraint *con, ConstraintIDFunc func, void *
        bLockTrackConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int locktrack_get_tars (bConstraint *con, ListBase *list)
@@ -2584,7 +2584,7 @@ static void distlimit_id_looper (bConstraint *con, ConstraintIDFunc func, void *
        bDistLimitConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int distlimit_get_tars (bConstraint *con, ListBase *list)
@@ -2712,7 +2712,7 @@ static void stretchto_id_looper (bConstraint *con, ConstraintIDFunc func, void *
        bStretchToConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int stretchto_get_tars (bConstraint *con, ListBase *list)
@@ -2887,7 +2887,7 @@ static void minmax_id_looper (bConstraint *con, ConstraintIDFunc func, void *use
        bMinMaxConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int minmax_get_tars (bConstraint *con, ListBase *list)
@@ -3030,8 +3030,8 @@ static void rbj_id_looper (bConstraint *con, ConstraintIDFunc func, void *userda
        bRigidBodyJointConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
-       func(con, (ID**)&data->child, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
+       func(con, (ID**)&data->child, FALSE, userdata);
 }
 
 static int rbj_get_tars (bConstraint *con, ListBase *list)
@@ -3083,7 +3083,7 @@ static void clampto_id_looper (bConstraint *con, ConstraintIDFunc func, void *us
        bClampToConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int clampto_get_tars (bConstraint *con, ListBase *list)
@@ -3268,7 +3268,7 @@ static void transform_id_looper (bConstraint *con, ConstraintIDFunc func, void *
        bTransformConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int transform_get_tars (bConstraint *con, ListBase *list)
@@ -3403,10 +3403,10 @@ static bConstraintTypeInfo CTI_TRANSFORM = {
 
 static void shrinkwrap_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
 {
-       bShrinkwrapConstraint *data= con->data;
+       bShrinkwrapConstraint *data = con->data;
        
        /* target only */
-       func(con, (ID**)&data->target, userdata);
+       func(con, (ID**)&data->target, FALSE, userdata);
 }
 
 static int shrinkwrap_get_tars (bConstraint *con, ListBase *list)
@@ -3571,7 +3571,7 @@ static void damptrack_id_looper (bConstraint *con, ConstraintIDFunc func, void *
        bDampTrackConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int damptrack_get_tars (bConstraint *con, ListBase *list)
@@ -3717,7 +3717,7 @@ static void splineik_id_looper (bConstraint *con, ConstraintIDFunc func, void *u
        bSplineIKConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int splineik_get_tars (bConstraint *con, ListBase *list)
@@ -3790,7 +3790,7 @@ static void pivotcon_id_looper (bConstraint *con, ConstraintIDFunc func, void *u
        bPivotConstraint *data= con->data;
        
        /* target only */
-       func(con, (ID**)&data->tar, userdata);
+       func(con, (ID**)&data->tar, FALSE, userdata);
 }
 
 static int pivotcon_get_tars (bConstraint *con, ListBase *list)
@@ -3922,9 +3922,9 @@ static void followtrack_id_looper(bConstraint *con, ConstraintIDFunc func, void
 {
        bFollowTrackConstraint *data = con->data;
 
-       func(con, (ID**)&data->clip, userdata);
-       func(con, (ID**)&data->camera, userdata);
-       func(con, (ID**)&data->depth_ob, userdata);
+       func(con, (ID**)&data->clip, TRUE, userdata);
+       func(con, (ID**)&data->camera, FALSE, userdata);
+       func(con, (ID**)&data->depth_ob, FALSE, userdata);
 }
 
 static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
@@ -4116,7 +4116,7 @@ static void camerasolver_id_looper(bConstraint *con, ConstraintIDFunc func, void
 {
        bCameraSolverConstraint *data = con->data;
 
-       func(con, (ID**)&data->clip, userdata);
+       func(con, (ID**)&data->clip, TRUE, userdata);
 }
 
 static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
@@ -4172,8 +4172,8 @@ static void objectsolver_id_looper(bConstraint *con, ConstraintIDFunc func, void
 {
        bObjectSolverConstraint *data= con->data;
 
-       func(con, (ID**)&data->clip, userdata);
-       func(con, (ID**)&data->camera, userdata);
+       func(con, (ID**)&data->clip, FALSE, userdata);
+       func(con, (ID**)&data->camera, FALSE, userdata);
 }
 
 static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
@@ -4535,12 +4535,20 @@ void id_loop_constraints(ListBase *conlist, ConstraintIDFunc func, void *userdat
 /* ......... */
 
 /* helper for copy_constraints(), to be used for making sure that ID's are valid */
-static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, void *UNUSED(userData))
+static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, short UNUSED(isReference), void *UNUSED(userData))
 {
        if (*idpoin && (*idpoin)->lib)
                id_lib_extern(*idpoin);
 }
 
+/* helper for copy_constraints(), to be used for making sure that usercounts of copied ID's are fixed up */
+static void con_fix_copied_refs_cb(bConstraint *con, ID **idpoin, short isReference, void *UNUSED(userData))
+{
+       /* increment usercount if this is a reference type */
+       if ((*idpoin) && (isReference))
+               id_us_plus(*idpoin);
+}
+
 /* duplicate all of the constraints in a constraint stack */
 void copy_constraints(ListBase *dst, const ListBase *src, int do_extern)
 {
@@ -4560,6 +4568,10 @@ void copy_constraints(ListBase *dst, const ListBase *src, int do_extern)
                        /* perform custom copying operations if needed */
                        if (cti->copy_data)
                                cti->copy_data(con, srccon);
+                               
+                       /* fix usercounts for all referenced data in referenced data */
+                       if (cti->id_looper)
+                               cti->id_looper(con, con_fix_copied_refs_cb, NULL);
                        
                        /* for proxies we don't want to make extern */
                        if (do_extern) {
index 231c1ab8d03d811876e7aca8890eb0ae0bc7f745..ec7d58035b4d70ac607c4d7c0b8873add561c4cf 100644 (file)
@@ -2473,10 +2473,19 @@ typedef struct tConstraintLinkData {
        ID *id;
 } tConstraintLinkData;
 /* callback function used to relink constraint ID-links */
-static void lib_link_constraint_cb(bConstraint *UNUSED(con), ID **idpoin, void *userdata)
+static void lib_link_constraint_cb(bConstraint *UNUSED(con), ID **idpoin, short isReference, void *userdata)
 {
        tConstraintLinkData *cld= (tConstraintLinkData *)userdata;
-       *idpoin = newlibadr(cld->fd, cld->id->lib, *idpoin);
+       
+       /* for reference types, we need to increment the usercounts on load... */
+       if (isReference) {
+               /* reference type - with usercount */
+               *idpoin = newlibadr_us(cld->fd, cld->id->lib, *idpoin);
+       }
+       else {
+               /* target type - no usercount needed */
+               *idpoin = newlibadr(cld->fd, cld->id->lib, *idpoin);
+       }
 }
 
 static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
@@ -8115,7 +8124,7 @@ typedef struct tConstraintExpandData {
        Main *mainvar;
 } tConstraintExpandData;
 /* callback function used to expand constraint ID-links */
-static void expand_constraint_cb(bConstraint *UNUSED(con), ID **idpoin, void *userdata)
+static void expand_constraint_cb(bConstraint *UNUSED(con), ID **idpoin, short UNUSED(isReference), void *userdata)
 {
        tConstraintExpandData *ced= (tConstraintExpandData *)userdata;
        expand_doit(ced->fd, ced->mainvar, *idpoin);
index 94ea79099c29163c39fbc6c97f639f324eb85ccc..06352fd727c4b76f9a2178e7215ac7d37a9567b6 100644 (file)
@@ -837,7 +837,7 @@ void rna_def_animdata(BlenderRNA *brna)
        /* Active Action */
        prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
                /* this flag as well as the dynamic test must be defined for this to be editable... */
-       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_flag(prop, PROP_EDITABLE|PROP_ID_REFCOUNT);
        RNA_def_property_pointer_funcs(prop, NULL, "rna_AnimData_action_set", NULL, "rna_Action_id_poll");
        RNA_def_property_editable_func(prop, "rna_AnimData_action_editable");
        RNA_def_property_ui_text(prop, "Action", "Active Action for this datablock");
index e321e83dd615fd01c8f8c0f3b92fa291e84d7189..b812c574a01fec5b24056fecb5b5d02780bf491b 100644 (file)
@@ -562,7 +562,7 @@ static void rna_def_constraint_python(BlenderRNA *brna)
 
        prop = RNA_def_property(srna, "text", PROP_POINTER, PROP_NONE);
        RNA_def_property_ui_text(prop, "Script", "The text object that contains the Python script");
-       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_flag(prop, PROP_EDITABLE|PROP_ID_REFCOUNT);
        RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
 
        prop = RNA_def_property(srna, "use_targets", PROP_BOOLEAN, PROP_NONE);
@@ -1097,7 +1097,7 @@ static void rna_def_constraint_action(BlenderRNA *brna)
        prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
        RNA_def_property_pointer_sdna(prop, NULL, "act");
        RNA_def_property_ui_text(prop, "Action", "The constraining action");
-       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_flag(prop, PROP_EDITABLE|PROP_ID_REFCOUNT);
        RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
 
        prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME);
index 8d262c58f9b7d37baed36c7230a038d1679efb98..7ad13b8a6d1062512955e4395fdfbfe81d74dfd4 100644 (file)
@@ -459,7 +459,7 @@ static void rna_def_nlastrip(BlenderRNA *brna)
        prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
        RNA_def_property_pointer_sdna(prop, NULL, "act");
        RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Action_id_poll");
-       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_flag(prop, PROP_EDITABLE|PROP_ID_REFCOUNT);
        RNA_def_property_editable_func(prop, "rna_NlaStrip_action_editable");
        RNA_def_property_ui_text(prop, "Action", "Action referenced by this strip");
        RNA_def_property_update(prop, NC_ANIMATION|ND_NLA, NULL); /* this will do? */