Exemplo n.º 1
0
/** Similar to libblock_relink_ex, but is remapping IDs to their newid value if non-NULL, in given \a id.
 *
 * Very specific usage, not sure we'll keep it on the long run, currently only used in Object duplication code...
 */
void BKE_libblock_relink_to_newid(ID *id)
{
	if (ID_IS_LINKED(id))
		return;

	BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0);
}
Exemplo n.º 2
0
/** Generate the mappings between used IDs and their users, and vice-versa. */
void BKE_main_relations_create(Main *bmain)
{
  if (bmain->relations != NULL) {
    BKE_main_relations_free(bmain);
  }

  bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
  bmain->relations->id_used_to_user = BLI_ghash_new(
      BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
  bmain->relations->id_user_to_used = BLI_ghash_new(
      BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
  bmain->relations->entry_pool = BLI_mempool_create(
      sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);

  ID *id;
  FOREACH_MAIN_ID_BEGIN (bmain, id) {
    BKE_library_foreach_ID_link(
        NULL, id, main_relations_create_idlink_cb, bmain->relations, IDWALK_READONLY);
  }
Exemplo n.º 3
0
/**
 * 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 within given \a id.
 *
 * \param bmain: the Main data storage to operate on (must never be NULL).
 * \param id: the datablock to operate on (can be NULL, in which case we operate over all IDs from given bmain).
 * \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 r_id_remap_data: if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
 */
ATTR_NONNULL(1) 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->bmain = bmain;
	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 (id) {
#ifdef DEBUG_PRINT
		printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
#endif
		r_id_remap_data->id = id;
		libblock_remap_data_preprocess(r_id_remap_data);
		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;

			if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) {
				continue;
			}

			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). */
				r_id_remap_data->id = id_curr;
				libblock_remap_data_preprocess(r_id_remap_data);
				BKE_library_foreach_ID_link(
				            id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
			}
		}
	}

	if (old_id && GS(old_id->name) == ID_OB) {
		BKE_sca_logic_links_remap(bmain, (Object *)old_id, (Object *)new_id);
	}

	/* 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;
	}

#ifdef DEBUG_PRINT
	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);
#endif
}
Exemplo n.º 4
0
static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
#if 0  /* If someone knows how to get a proper 'self' in that case... */
	BPy_StructRNA *pyrna = (BPy_StructRNA *)self;
	Main *bmain = pyrna->ptr.data;
#else
	Main *bmain = G.main;  /* XXX Ugly, but should work! */
#endif

	static const char *kwlist[] = {"subset", "key_types", "value_types", NULL};
	PyObject *subset = NULL;

	PyObject *key_types = NULL;
	PyObject *val_types = NULL;
	BLI_bitmap *key_types_bitmap = NULL;
	BLI_bitmap *val_types_bitmap = NULL;

	PyObject *ret = NULL;


	if (!PyArg_ParseTupleAndKeywords(
	        args, kwds, "|O$O!O!:user_map", (char **)kwlist,
	        &subset,
	        &PySet_Type, &key_types,
	        &PySet_Type, &val_types))
	{
		return NULL;
	}

	if (key_types) {
		key_types_bitmap = pyrna_set_to_enum_bitmap(
		        rna_enum_id_type_items, key_types, sizeof(short), true, USHRT_MAX, "key types");
		if (key_types_bitmap == NULL) {
			goto error;
		}
	}

	if (val_types) {
		val_types_bitmap = pyrna_set_to_enum_bitmap(
		        rna_enum_id_type_items, val_types, sizeof(short), true, USHRT_MAX, "value types");
		if (val_types_bitmap == NULL) {
			goto error;
		}
	}

	IDUserMapData data_cb = {NULL};

	if (subset) {
		PyObject *subset_fast = PySequence_Fast(subset, "user_map");
		if (subset_fast == NULL) {
			goto error;
		}

		PyObject **subset_array = PySequence_Fast_ITEMS(subset_fast);
		Py_ssize_t subset_len = PySequence_Fast_GET_SIZE(subset_fast);

		data_cb.user_map = _PyDict_NewPresized(subset_len);
		data_cb.is_subset = true;
		for (; subset_len; subset_array++, subset_len--) {
			PyObject *set = PySet_New(NULL);
			PyDict_SetItem(data_cb.user_map, *subset_array, set);
			Py_DECREF(set);
		}
		Py_DECREF(subset_fast);
	}
	else {
		data_cb.user_map = PyDict_New();
	}

	data_cb.types_bitmap = key_types_bitmap;

	ListBase *lb_array[MAX_LIBARRAY];
	int lb_index;
	lb_index = set_listbasepointers(bmain, lb_array);

	while (lb_index--) {

		if (val_types_bitmap && lb_array[lb_index]->first) {
			if (!id_check_type(lb_array[lb_index]->first, val_types_bitmap)) {
				continue;
			}
		}

		for (ID *id = lb_array[lb_index]->first; id; id = id->next) {
			/* One-time init, ID is just used as placeholder here, we abuse this in iterator callback
			 * to avoid having to rebuild a complete bpyrna object each time for the key searching
			 * (where only ID pointer value is used). */
			if (data_cb.py_id_key_lookup_only == NULL) {
				data_cb.py_id_key_lookup_only = pyrna_id_CreatePyObject(id);
			}

			if (!data_cb.is_subset) {
				PyObject *key = data_cb.py_id_key_lookup_only;
				PyObject *set;

				RNA_id_pointer_create(id, &((BPy_StructRNA *)key)->ptr);

				/* We have to insert the key now, otherwise ID unused would be missing from final dict... */
				if ((set = PyDict_GetItem(data_cb.user_map, key)) == NULL) {
					/* Cannot use our placeholder key here! */
					key = pyrna_id_CreatePyObject(id);
					set = PySet_New(NULL);
					PyDict_SetItem(data_cb.user_map, key, set);
					Py_DECREF(set);
					Py_DECREF(key);
				}
			}

			data_cb.id_curr = id;
			BKE_library_foreach_ID_link(id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_NOP);

			if (data_cb.py_id_curr) {
				Py_DECREF(data_cb.py_id_curr);
				data_cb.py_id_curr = NULL;
			}
		}
	}

	ret = data_cb.user_map;


error:

	Py_XDECREF(data_cb.py_id_key_lookup_only);

	if (key_types_bitmap) {
		MEM_freeN(key_types_bitmap);
	}

	if (val_types_bitmap) {
		MEM_freeN(val_types_bitmap);
	}

	return ret;

}