[Bf-blender-cvs] [aabe83d] id-remap: Merge branch 'libquery-recursive' into id-remap

Bastien Montagne noreply at git.blender.org
Fri Feb 19 10:53:19 CET 2016


Commit: aabe83d4c0b80eec8e9286d75476060d958a4d37
Author: Bastien Montagne
Date:   Fri Feb 19 10:50:26 2016 +0100
Branches: id-remap
https://developer.blender.org/rBaabe83d4c0b80eec8e9286d75476060d958a4d37

Merge branch 'libquery-recursive' into id-remap

Conflicts:
	source/blender/blenkernel/intern/library_query.c

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



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

diff --cc source/blender/blenkernel/intern/library.c
index 61b65e3,c403319..6b95b6c
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@@ -1077,381 -1111,11 +1077,381 @@@ void BKE_library_callback_free_notifier
  	free_notifier_reference_cb = func;
  }
  
 -static BKE_library_free_editor_id_reference_cb free_editor_id_reference_cb = NULL;
 +static BKE_library_remap_editor_id_reference_cb remap_editor_id_reference_cb = NULL;
 +
 +void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func)
 +{
 +	remap_editor_id_reference_cb = func;
 +}
 +
 +typedef struct IDRemap {
 +	ID *old_id;
 +	ID *new_id;
 +	ID *id;  /* The ID in which we are replacing old_id by new_id usages. */
 +	short flag;
 +
 +	/* 'Output' data. */
 +	short status;
 +	int skipped_direct;  /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */
 +	int skipped_indirect;  /* Number of indirect usecases that could not be remapped. */
 +	int skipped_refcounted;  /* Number of skipped usecases that refcount the datablock. */
 +} IDRemap;
 +
 +/* IDRemap->flag enums defined in BKE_library.h */
 +
 +/* IDRemap->status */
 +enum {
 +	/* *** Set by callback. *** */
 +	ID_REMAP_IS_LINKED_DIRECT       = 1 << 0,  /* new_id is directly linked in current .blend. */
 +	ID_REMAP_IS_USER_ONE_SKIPPED    = 1 << 1,  /* There was some skipped 'user_one' usages of old_id. */
 +};
 +
- static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag)
++static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), ID **id_p, int cb_flag)
 +{
 +	IDRemap *id_remap_data = user_data;
 +	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_TAG_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));
 +		/* Note that indirect data from same file as processed ID is **not** considered indirect! */
 +		const bool is_indirect = ((id->lib != NULL) && (id->lib != old_id->lib));
 +		const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
 +		const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) &&
 +		                            (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
 +		const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
 +
 +		if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) {
 +			id->tag |= LIB_TAG_DOIT;
 +		}
 +
 +//		if (GS(old_id->name) == ID_TXT) {
 +//			printf("\t\t %s (from %s) (%d)\n", old_id->name, old_id->lib ? old_id->lib->filepath : "<MAIN>", old_id->us);
 +//			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 : "<NONE>", new_id);
 +//		}
 +
 +		/* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
 +		if ((is_never_null && skip_never_null) ||
 +		    (is_obj_editmode && (((Object *)id)->data == *id_p)) ||
 +		    (skip_indirect && (is_proxy || is_indirect)))
 +		{
 +			if (is_never_null || is_proxy || is_obj_editmode) {
 +				id_remap_data->skipped_direct++;
 +			}
 +			else {
 +				id_remap_data->skipped_indirect++;
 +			}
 +			if (cb_flag & IDWALK_USER) {
 +				id_remap_data->skipped_refcounted++;
 +			}
 +			else if (cb_flag & IDWALK_USER_ONE) {
 +				/* No need to count number of times this happens, just a flag is enough. */
 +				id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
 +			}
 +		}
 +		else {
 +			if (!is_never_null) {
 +				*id_p = new_id;
 +			}
 +			if (cb_flag & IDWALK_USER) {
 +				id_us_min(old_id);
 +				/* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
 +				if (new_id)
 +					new_id->us++;
 +			}
 +			else if (cb_flag & IDWALK_USER_ONE) {
 +				id_us_ensure_real(new_id);
 +				/* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed,
 +				 * that extra user is processed in final handling... */
 +			}
 +			if (!is_indirect) {
 +				id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
 +			}
 +		}
 +	}
 +
 +	return IDWALK_RET_NOP;
 +}
 +
 +/**
 + * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
 + *
 + * Behavior differs depending on whether given \a id is NULL or not:
 + *   - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not
 + *     (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id
 + *     are remapped to \a new_id.
 + *   - \a id is non-NULL:
 + *     + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id
 + *       does not references any other datablock anymore).
 + *     + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id.
 + *
 + * \param bmain the Main data storage to operate on (can be NULL if \a id is non-NULL).
 + * \param id the datablock to operate on (can be NULL if \a bmain is non-NULL).
 + * \param old_id the datablock to dereference (may be NULL if \a id is non-NULL).
 + * \param new_id the new datablock to replace \a old_id references with (may be NULL).
 + * \param skip_indirect_usage if true, do not remap/unlink indirect usages of \a old_id datablock.
 + * \param r_id_remap_data if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
 + * \return true is there was some 'user_one' users of \a old_id (needed to handle correctly #old_id->us count).
 + */
 +static void libblock_remap_data(
 +        Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data)
 +{
 +	IDRemap id_remap_data;
 +	ListBase *lb_array[MAX_LIBARRAY];
 +	int i;
 +
 +	if (r_id_remap_data == NULL) {
 +		r_id_remap_data = &id_remap_data;
 +	}
 +	r_id_remap_data->old_id = old_id;
 +	r_id_remap_data->new_id = new_id;
 +	r_id_remap_data->id = NULL;
 +	r_id_remap_data->flag = remap_flags;
 +	r_id_remap_data->status = 0;
 +	r_id_remap_data->skipped_direct = 0;
 +	r_id_remap_data->skipped_indirect = 0;
 +	r_id_remap_data->skipped_refcounted = 0;
 +
 +//	if (old_id && GS(old_id->name) == ID_AC)
 +//		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 (id) {
 +//		printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
 +		r_id_remap_data->id = id;
 +		BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_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_curr = lb_array[i]->first;
 +
 +			for (; id_curr; id_curr = id_curr->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). */
 +//				if (GS(old_id->name) == ID_AC && STRCASEEQ(id_curr->name, "OBfranck_blenrig"))
 +//					printf("\tchecking id %s (%p, %p)\n", id_curr->name, id_curr, id_curr->lib);
 +				r_id_remap_data->id = id_curr;
 +				BKE_library_foreach_ID_link(
 +				            id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
 +			}
 +		}
 +	}
 +
 +	/* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
 +	 *     though, we can always add an option (flag) to control this later if needed. */
 +	if (old_id && (old_id->flag & LIB_FAKEUSER)) {
 +		id_fake_user_clear(old_id);
 +		id_fake_user_set(new_id);
 +	}
 +
 +	id_us_clear_real(old_id);
 +
 +	if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
 +		new_id->tag &= ~LIB_TAG_INDIRECT;
 +		new_id->tag |= LIB_TAG_EXTERN;
 +	}
 +
 +//	printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__,
 +//	       r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect,
 +//	       r_id_remap_data->skipped_direct, r_id_remap_data->skipped_indirect);
 +}
 +
 +/**
 + * Replace all references in given Main to \a old_id by \a new_id (if \a new_id is NULL, it unlinks \a old_id).
 + *
 + * \param skip_indirect_usage If \a true, indirect usages (like e.g. by other linked datablocks) are not remapped.
 + * \param do_flag_never_null If \a true, 'NEVER_NULL' ID users are flagged with LIB_TAG_DOIT (caller is expected
 + *                           to ensure that flag is correctly unset first).
 + */
 +void BKE_libblock_remap_locked(
 +        Main *bmain, void *old_idv, void *new_idv,
 +        const short remap_flags)
 +{
 +	IDRemap id_remap_data;
 +	ID *old_id = old_idv;
 +	ID *new_id = new_idv;
 +	int skipped_direct, skipped_refcounted;
 +
 +	BLI_assert(old_id != NULL);
 +	BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
 +	BLI_assert(old_id != new_id);
 +
 +	/* Some pre-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 (new_ob == NULL) {
 +			Scene *sce;
 +			Base *base;
 +
 +			for (sce = bmain->s

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list