[Bf-blender-cvs] [e0c7dcb] id-remap: Merge branch 'master' into id-remap

Bastien Montagne noreply at git.blender.org
Thu Oct 8 12:45:59 CEST 2015


Commit: e0c7dcba5b6d680c2b28d1eb8ec32ca5683546a1
Author: Bastien Montagne
Date:   Thu Oct 8 12:43:41 2015 +0200
Branches: id-remap
https://developer.blender.org/rBe0c7dcba5b6d680c2b28d1eb8ec32ca5683546a1

Merge branch 'master' into id-remap

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



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

diff --cc source/blender/blenkernel/BKE_library.h
index cbc0235,4fab910..904507c
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@@ -56,17 -54,8 +56,18 @@@ void *BKE_libblock_copy_ex(struct Main 
  void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL();
  void *BKE_libblock_copy(struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
  void  BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action);
+ void  BKE_libblock_relink(struct ID *id);
  
 +/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */
 +void BKE_libblock_remap_locked(
 +        struct Main *bmain, void *old_id, void *new_id, const bool skip_indirect_usage) ATTR_NONNULL(1, 2);
 +void BKE_libblock_remap(
 +        struct Main *bmain, void *old_idv, void *new_idv, const bool skip_indirect_usage) ATTR_NONNULL(1, 2);
 +
 +void BKE_libblock_unlink(struct Main *bmain, void *idv) ATTR_NONNULL();
 +
- void BKE_libblock_relink(struct Main *bmain, void *idv, void *old_idv, void *new_idv) ATTR_NONNULL(1, 2);
++void BKE_libblock_relink_ex(struct Main *bmain, void *idv, void *old_idv, void *new_idv) ATTR_NONNULL(1, 2);
 +
  void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
  void id_lib_extern(struct ID *id);
  void BKE_library_filepath_set(struct Library *lib, const char *filepath);
diff --cc source/blender/blenkernel/intern/library.c
index 0237de5,d6b2a3c..f473057
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@@ -951,7 -865,32 +951,32 @@@ void *BKE_libblock_copy(ID *id
  	return BKE_libblock_copy_ex(G.main, id);
  }
  
+ static bool id_relink_looper(void *UNUSED(user_data), ID **id_pointer, const int cd_flag)
+ {
+ 	ID *id = *id_pointer;
+ 	if (id) {
+ 		/* See: NEW_ID macro */
+ 		if (id->newid) {
+ 			BKE_library_update_ID_link_user(id->newid, id, cd_flag);
+ 			*id_pointer = id->newid;
+ 		}
+ 		else if (id->flag & LIB_NEW) {
+ 			id->flag &= ~LIB_NEW;
+ 			BKE_libblock_relink(id);
+ 		}
+ 	}
+ 	return true;
+ }
+ 
+ void BKE_libblock_relink(ID *id)
+ {
+ 	if (id->lib)
+ 		return;
+ 
+ 	BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
+ }
+ 
 -static void BKE_library_free(Library *lib)
 +static void library_free(Library *lib)
  {
  	if (lib->packedfile)
  		freePackedFile(lib->packedfile);
@@@ -971,286 -910,11 +996,286 @@@ void BKE_library_callback_free_notifier
  	free_notifier_reference_cb = func;
  }
  
 -static void (*free_editor_id_reference_cb)(const ID *) = NULL;
 +static void (*remap_editor_id_reference_cb)(ID *, ID *) = NULL;
  
 -void BKE_library_callback_free_editor_id_reference_set(void (*func)(const ID *))
 +void BKE_library_callback_remap_editor_id_reference_set(void (*func)(ID *, ID *))
  {
 -	free_editor_id_reference_cb = func;
 +	remap_editor_id_reference_cb = func;
 +}
 +
 +typedef struct IDRemap {
 +	Main *bmain;
 +	ID *old_id;
 +	ID *new_id;
 +	ID *id;  /* The ID in which we are replacing old_id by new_id usages. */
 +	/* XXX TODO: keeping this for now (also as debug data), in theory we can get rid of it. */
 +	int skipped_direct;  /* Number of direct usecase that could not be remapped (e.g.: obdata when in edit mode). */
 +	int skipped_indirect;  /* Number of indirect usecase that could not be remapped. */
 +	int flag;
 +} IDRemap;
 +
 +enum {
 +	/* Set by caller. */
 +	ID_REMAP_SKIP_INDIRECT_USAGE  = 1 << 0,
 +
 +	/* Set by callback. */
 +	ID_REMAP_IS_LINKED_DIRECT     = 1 << 16,  /* new_id is directly linked in current .blend. */
 +};
 +
 +static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_flag)
 +{
 +	IDRemap *id_remap_data = user_data;
 +	Main *bmain = id_remap_data->bmain;
 +	ID *old_id = id_remap_data->old_id;
 +	ID *new_id = id_remap_data->new_id;
 +	ID *id = id_remap_data->id;
 +
 +	if (!old_id) {  /* Used to cleanup all IDs used by a specific one. */
 +		BLI_assert(!new_id);
 +		old_id = *id_p;
 +	}
 +
 +	if (*id_p && (*id_p == old_id)) {
 +		/* Note: proxy usage implies LIB_EXTERN, so on this aspect it is direct,
 +		 *       on the other hand since they get reset to lib data on file open/reload it is indirect too...
 +		 *       Edit Mode is also a 'skip direct' case. */
 +		const bool is_obj = (GS(id->name) == ID_OB);
 +		const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
 +		const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
 +		const bool is_indirect = (id->lib != NULL);
 +		const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
 +
 +		printf("\t\tIn %s (%p): remapping %s (%p) to %s (%p)\n",
 +		       id->name, id, old_id->name, old_id, new_id ? new_id->name : "", new_id);
 +
 +		/* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
 +		if ((is_obj_editmode && (((Object *)id)->data == *id_p)) || (skip_indirect && (is_proxy || is_indirect))) {
 +			if (is_proxy || is_obj_editmode) {
 +				id_remap_data->skipped_direct++;
 +			}
 +			else {
 +				id_remap_data->skipped_indirect++;
 +			}
 +		}
 +		else {
 +			*id_p = new_id;
- 			if (cb_flag & IDWALK_REFCOUNTED) {
++			if (cb_flag & IDWALK_USER) {
 +				old_id->us--;
 +				if (new_id)
 +					new_id->us++;
 +			}
 +			DAG_id_tag_update_ex(bmain, id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 +			if (!is_indirect) {
 +				id_remap_data->flag |= ID_REMAP_IS_LINKED_DIRECT;
 +			}
 +		}
 +	}
 +
 +	return true;
 +}
 +
 +static void libblock_remap_do(
 +        Main *bmain, ID *id, ID *old_id, ID *new_id, const bool skip_indirect_usage,
 +        int *r_skipped_direct, int *r_skipped_indirect)
 +{
 +	IDRemap id_remap_data = {bmain, old_id, new_id, NULL};
 +	ListBase *lb_array[MAX_LIBARRAY];
 +	int i;
 +
 +	printf("%s: %s (%p) replaced by %s (%p)\n", __func__,
 +	       old_id ? old_id->name : "", old_id, new_id ? new_id->name : "", new_id);
 +
 +	if (skip_indirect_usage) {
 +		id_remap_data.flag |= ID_REMAP_SKIP_INDIRECT_USAGE;
 +	}
 +
 +	if (id) {
 +		printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
 +		id_remap_data.id = id;
 +		BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)&id_remap_data, IDWALK_NOP);
 +	}
 +	else {
 +		i = set_listbasepointers(bmain, lb_array);
 +
 +		/* Note that this is a very 'bruteforce' approach, maybe we could use some depsgraph to only process
 +		 * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */
 +
 +		while (i--) {
 +			ID *id = lb_array[i]->first;
 +
 +			for (; id; id = id->next) {
 +				/* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
 +				 * the user count handling...
 +				 * XXX No more true (except for debug usage of those skipping counters). */
 +				printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
 +				id_remap_data.id = id;
 +				BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)&id_remap_data, IDWALK_NOP);
 +			}
 +		}
 +	}
 +
 +	if (old_id->flag & LIB_FAKEUSER) {
 +		id_remap_data.skipped_direct++;
 +	}
 +
 +	if (new_id && (new_id->flag & LIB_INDIRECT) && (id_remap_data.flag & ID_REMAP_IS_LINKED_DIRECT)) {
 +		new_id->flag &= ~LIB_INDIRECT;
 +		new_id->flag |= LIB_EXTERN;
 +	}
 +
 +	if (r_skipped_direct)
 +		*r_skipped_direct = id_remap_data.skipped_direct;
 +
 +	if (r_skipped_indirect)
 +		*r_skipped_indirect = id_remap_data.skipped_indirect;
 +
 +	printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__,
 +	       id_remap_data.skipped_direct + id_remap_data.skipped_indirect,
 +	       id_remap_data.skipped_direct, id_remap_data.skipped_indirect);
 +}
 +
 +/** Replace all references in .blend file to \a old_id by \a new_id (if \a new_id is NULL, it unlinks \a old_id). */
 +void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const bool skip_indirect_usage)
 +{
 +	ID *old_id = old_idv;
 +	ID *new_id = new_idv;
 +	int skipped_direct;
 +
 +	BLI_assert(old_id != NULL);
 +	BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
 +	BLI_assert(old_id != new_id);
 +
 +	printf("%s: %s (%p) replaced by %s (%p)\n", __func__, old_id->name, old_id, new_id ? new_id->name : "", new_id);
 +
 +	/* Some pre-processing.
 +	 * This is a bit ugly, but cannot see a way to avoid it...
 +	 */
 +	if (GS(old_id->name) == ID_OB) {
 +		Object *old_ob = (Object *)old_id;
 +		Scene *sce;
 +		Base *base;
 +
 +		for (sce = bmain->scene.first; sce; sce = sce->id.next) {
 +			base = BKE_scene_base_find(sce, old_ob);
 +
 +			if (base) {
 +				BKE_scene_base_unlink(sce, base);
 +				base->object->id.us--;
 +				MEM_freeN(base);
 +			}
 +		}
 +	}
 +
 +	libblock_remap_do(bmain, NULL, old_id, new_id, skip_indirect_usage, &skipped_direct, NULL);
 +
 +	if (free_notifier_reference_cb) {
 +		free_notifier_reference_cb(old_id);
 +	}
 +
 +	/* We assume editors do not hold references to their IDs... This is false in some cases
 +	 * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */
 +	if (remap_editor_id_reference_cb) {
 +		remap_editor_id_reference_cb(old_id, new_id);
 +	}
 +
 +	BLI_assert(old_id->us >= 0);
 +
 +#if 0
 +	/* All ID 'users' do not actually incref it, so we just assume all uses of this ID have been cleared... */
 +	BLI_assert(old_id->us - skipped >= 0);
 +	if (new_id)
 +		new_id->us += old_id->us - skipped;
 +	old_id->us = skipped;
 +#endif
 +
 +	if (skipped_direct == 0) {
 +		/* old_id is assumed to not be used directly anymore... */
 +		if (old_id->lib && (old_id->flag & LIB_EXTERN)) {
 +			old_id->flag &= ~LIB_EXTERN;
 +			old_id->flag |= LIB_INDIRECT;
 +		}
 +	}
 +
 +	/* Some after-process updates.
 +	 * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
 +	 */
 +	if (GS(old_id->name) == ID_OB) {
 +		Object *old_ob = (Object *)old_id;
 +		Object *new_ob = (Object *)new_id;
 +
 +		if (old_ob->flag & OB_FROMGROUP) {
 +			/* Note that for Scene's BaseObject->flag, either we:
 +			 *     - unlinked old_ob (i.e. new_ob is

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list