[Bf-blender-cvs] [f097e73a2aa] master: Fix crash when making local object+obdata with linked armature.

Bastien Montagne noreply at git.blender.org
Fri Jun 9 16:31:17 CEST 2017


Commit: f097e73a2aa08234c6fbffc3af39620ab523dbd8
Author: Bastien Montagne
Date:   Fri Jun 9 15:58:32 2017 +0200
Branches: master
https://developer.blender.org/rBf097e73a2aa08234c6fbffc3af39620ab523dbd8

Fix crash when making local object+obdata with linked armature.

Reported by Andy Goralczyk (@eyecandy) over IRC, thanks!

Simply nuke all that poor broken custom one-by-one handling in
object_relations.c code, and use highly complex but powerful and
well-tested BKE_library_make_local() in all cases of MakeLocal!

ID management, especially related to linking, is very hairy matters,
better to have as few as possible core functions managing all the dirty
details. ;)

===================================================================

M	source/blender/editors/object/object_relations.c

===================================================================

diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 7ec43b02b38..3284af2df69 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2149,24 +2149,6 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo
 
 /******************************* Make Local ***********************************/
 
-/* helper for below, ma was checked to be not NULL */
-static void make_local_makelocalmaterial(Material *ma)
-{
-	AnimData *adt;
-	int b;
-
-	id_make_local(G.main, &ma->id, false, false);
-
-	for (b = 0; b < MAX_MTEX; b++)
-		if (ma->mtex[b] && ma->mtex[b]->tex)
-			id_make_local(G.main, &ma->mtex[b]->tex->id, false, false);
-
-	adt = BKE_animdata_from_id(&ma->id);
-	if (adt) BKE_animdata_make_local(adt);
-
-	/* nodetree? XXX */
-}
-
 enum {
 	MAKE_LOCAL_SELECT_OB              = 1,
 	MAKE_LOCAL_SELECT_OBDATA          = 2,
@@ -2252,123 +2234,142 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene)
 	return changed;
 }
 
-static int make_local_exec(bContext *C, wmOperator *op)
+static void make_local_animdata_tag_strips(ListBase *strips)
 {
-	Main *bmain = CTX_data_main(C);
-	Scene *scene = CTX_data_scene(C);
-	AnimData *adt;
-	ParticleSystem *psys;
-	Material *ma, ***matarar;
-	Lamp *la;
-	ID *id;
-	const int mode = RNA_enum_get(op->ptr, "type");
-	int a, b;
+	NlaStrip *strip;
 
-	if (mode == MAKE_LOCAL_ALL) {
-		/* de-select so the user can differentiate newly instanced from existing objects */
-		BKE_scene_base_deselect_all(scene);
-
-		if (make_local_all__instance_indirect_unused(bmain, scene)) {
-			BKE_report(op->reports, RPT_INFO,
-			           "Orphan library objects added to the current scene to avoid loss");
+	for (strip = strips->first; strip; strip = strip->next) {
+		if (strip->act) {
+			strip->act->id.tag &= ~LIB_TAG_PRE_EXISTING;
+		}
+		if (strip->remap && strip->remap->target) {
+			strip->remap->target->id.tag &= ~LIB_TAG_PRE_EXISTING;
 		}
 
-		BKE_library_make_local(bmain, NULL, NULL, false, false); /* NULL is all libs */
-		WM_event_add_notifier(C, NC_WINDOW, NULL);
-		return OPERATOR_FINISHED;
+		make_local_animdata_tag_strips(&strip->strips);
 	}
+}
 
-	tag_localizable_objects(C, mode);
-
-	CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
-	{
-		if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
-			continue;
+/* Tag all actions used by given animdata to be made local. */
+static void make_local_animdata_tag(AnimData *adt)
+{
+	if (adt) {
+		/* Actions - Active and Temp */
+		if (adt->action) {
+			adt->action->id.tag &= ~LIB_TAG_PRE_EXISTING;
+		}
+		if (adt->tmpact) {
+			adt->tmpact->id.tag &= ~LIB_TAG_PRE_EXISTING;
+		}
+		/* Remaps */
+		if (adt->remap && adt->remap->target) {
+			adt->remap->target->id.tag &= ~LIB_TAG_PRE_EXISTING;
 		}
 
-		if (ob->id.lib)
-			id_make_local(bmain, &ob->id, false, false);
-	}
-	CTX_DATA_END;
+		/* Drivers */
+		/* TODO: need to handle the ID-targets too? */
 
-	/* maybe object pointers */
-	CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
-	{
-		if (ob->id.lib == NULL) {
-			ID_NEW_REMAP(ob->parent);
+		/* NLA Data */
+		for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+			make_local_animdata_tag_strips(&nlt->strips);
 		}
 	}
-	CTX_DATA_END;
-
-	CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
-	{
-		if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
-			continue;
-		}
+}
 
-		id = ob->data;
+static void make_local_material_tag(Material *ma)
+{
+	if (ma) {
+		ma->id.tag &= ~LIB_TAG_PRE_EXISTING;
+		make_local_animdata_tag(BKE_animdata_from_id(&ma->id));
 
-		if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
-			id_make_local(bmain, id, false, false);
-			adt = BKE_animdata_from_id(id);
-			if (adt) BKE_animdata_make_local(adt);
+		/* About nodetrees: root one is made local together with material, others we keep linked for now... */
 
-			/* tag indirect data direct */
-			matarar = give_matarar(ob);
-			if (matarar) {
-				for (a = 0; a < ob->totcol; a++) {
-					ma = (*matarar)[a];
-					if (ma)
-						id_lib_extern(&ma->id);
-				}
+		for (int a = 0; a < MAX_MTEX; a++) {
+			if (ma->mtex[a] && ma->mtex[a]->tex) {
+				ma->mtex[a]->tex->id.tag &= ~LIB_TAG_PRE_EXISTING;
 			}
 		}
+	}
+}
 
-		for (psys = ob->particlesystem.first; psys; psys = psys->next)
-			id_make_local(bmain, &psys->part->id, false, false);
+static int make_local_exec(bContext *C, wmOperator *op)
+{
+	Main *bmain = CTX_data_main(C);
+	Scene *scene = CTX_data_scene(C);
+	ParticleSystem *psys;
+	Material *ma, ***matarar;
+	Lamp *la;
+	const int mode = RNA_enum_get(op->ptr, "type");
+	int a;
+
+	/* Note: we (ab)use LIB_TAG_PRE_EXISTING to cherry pick which ID to make local... */
+	if (mode == MAKE_LOCAL_ALL) {
+		BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+		/* de-select so the user can differentiate newly instanced from existing objects */
+		BKE_scene_base_deselect_all(scene);
 
-		adt = BKE_animdata_from_id(&ob->id);
-		if (adt) BKE_animdata_make_local(adt);
+		if (make_local_all__instance_indirect_unused(bmain, scene)) {
+			BKE_report(op->reports, RPT_INFO, "Orphan library objects added to the current scene to avoid loss");
+		}
 	}
-	CTX_DATA_END;
+	else {
+		BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+		tag_localizable_objects(C, mode);
 
-	if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) {
 		CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
 		{
 			if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
 				continue;
 			}
 
-			if (ob->type == OB_LAMP) {
-				la = ob->data;
-
-				for (b = 0; b < MAX_MTEX; b++)
-					if (la->mtex[b] && la->mtex[b]->tex)
-						id_make_local(bmain, &la->mtex[b]->tex->id, false, false);
+			ob->id.tag &= ~LIB_TAG_PRE_EXISTING;
+			make_local_animdata_tag(BKE_animdata_from_id(&ob->id));
+			for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+				psys->part->id.tag &= ~LIB_TAG_PRE_EXISTING;
 			}
-			else {
+
+			if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) {
 				for (a = 0; a < ob->totcol; a++) {
 					ma = ob->mat[a];
-					if (ma)
-						make_local_makelocalmaterial(ma);
+					if (ma) {
+						make_local_material_tag(ma);
+					}
 				}
 
 				matarar = (Material ***)give_matarar(ob);
 				if (matarar) {
 					for (a = 0; a < ob->totcol; a++) {
 						ma = (*matarar)[a];
-						if (ma)
-							make_local_makelocalmaterial(ma);
+						if (ma) {
+							make_local_material_tag(ma);
+						}
+					}
+				}
+
+				if (ob->type == OB_LAMP) {
+					BLI_assert(ob->data != NULL);
+					la = ob->data;
+					for (a = 0; a < MAX_MTEX; a++) {
+						if (la->mtex[a] && la->mtex[a]->tex) {
+							la->id.tag &= ~LIB_TAG_PRE_EXISTING;
+						}
 					}
 				}
 			}
+
+			if (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL) && ob->data != NULL) {
+				ID *ob_data = ob->data;
+				ob_data->tag &= ~LIB_TAG_PRE_EXISTING;
+				make_local_animdata_tag(BKE_animdata_from_id(ob_data));
+			}
 		}
 		CTX_DATA_END;
 	}
 
-	BKE_main_id_clear_newpoins(bmain);
-	WM_event_add_notifier(C, NC_WINDOW, NULL);
+	BKE_library_make_local(bmain, NULL, NULL, true, false); /* NULL is all libs */
 
+	WM_event_add_notifier(C, NC_WINDOW, NULL);
 	return OPERATOR_FINISHED;
 }




More information about the Bf-blender-cvs mailing list