示例#1
0
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
{
	BKE_main_lock(bmain);

	BKE_libblock_remap_locked(bmain, old_idv, new_idv, remap_flags);

	BKE_main_unlock(bmain);
}
示例#2
0
/**
 * Unlink given \a id from given \a bmain (does not touch to indirect, i.e. library, usages of the ID).
 *
 * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by \a LIB_TAG_DOIT flag
 * (quite obviously, 'non-NULL' usages can never be unlinked by this function...).
 */
void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null, const bool do_skip_indirect)
{
	const short remap_flags = (do_skip_indirect ? ID_REMAP_SKIP_INDIRECT_USAGE : 0) |
	                          (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0);

	BKE_main_lock(bmain);

	BKE_libblock_remap_locked(bmain, idv, NULL, remap_flags);

	BKE_main_unlock(bmain);
}
示例#3
0
/**
 * Allocates and returns a block of the specified type, with the specified name
 * (adjusted as necessary to ensure uniqueness), and appended to the specified list.
 * The user count is set to 1, all other content (apart from name and links) being
 * initialized to zero.
 */
void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
{
	ID *id = NULL;
	ListBase *lb = which_libbase(bmain, type);
	
	id = alloc_libblock_notest(type);
	if (id) {
		BKE_main_lock(bmain);
		BLI_addtail(lb, id);
		id->us = 1;
		id->icon_id = 0;
		*( (short *)id->name) = type;
		new_id(lb, id, name);
		/* alphabetic insertion: is in new_id */
		BKE_main_unlock(bmain);
	}
	DAG_id_type_tag(bmain, type);
	return id;
}
示例#4
0
/**
 * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
 *
 * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
 *                    (only applies to main database)
 * \param do_ui_user: similar to do_id_user but makes sure UI does not hold references to
 *                    \a id.
 */
void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user)
{
	ID *id = idv;
	short type = GS(id->name);
	ListBase *lb = which_libbase(bmain, type);

	DAG_id_type_tag(bmain, type);

#ifdef WITH_PYTHON
	BPY_id_release(id);
#endif

	if (do_id_user) {
		BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
	}

	BKE_libblock_free_datablock(id, 0);

	/* avoid notifying on removed data */
	BKE_main_lock(bmain);

	if (do_ui_user) {
		if (free_notifier_reference_cb) {
			free_notifier_reference_cb(id);
		}

		if (remap_editor_id_reference_cb) {
			remap_editor_id_reference_cb(id, NULL);
		}
	}

	BLI_remlink(lb, id);

	BKE_libblock_free_data(id, do_id_user);
	BKE_main_unlock(bmain);

	MEM_freeN(id);
}
示例#5
0
/**
 * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
 *
 * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
 */
void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
{
	ID *id = idv;
	short type = GS(id->name);
	ListBase *lb = which_libbase(bmain, type);

	DAG_id_type_tag(bmain, type);

#ifdef WITH_PYTHON
	BPY_id_release(id);
#endif

	if (do_id_user) {
		BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
	}

	switch (type) {
		case ID_SCE:
			BKE_scene_free((Scene *)id);
			break;
		case ID_LI:
			BKE_library_free((Library *)id);
			break;
		case ID_OB:
			BKE_object_free((Object *)id);
			break;
		case ID_ME:
			BKE_mesh_free((Mesh *)id);
			break;
		case ID_CU:
			BKE_curve_free((Curve *)id);
			break;
		case ID_MB:
			BKE_mball_free((MetaBall *)id);
			break;
		case ID_MA:
			BKE_material_free((Material *)id);
			break;
		case ID_TE:
			BKE_texture_free((Tex *)id);
			break;
		case ID_IM:
			BKE_image_free((Image *)id);
			break;
		case ID_LT:
			BKE_lattice_free((Lattice *)id);
			break;
		case ID_LA:
			BKE_lamp_free((Lamp *)id);
			break;
		case ID_CA:
			BKE_camera_free((Camera *) id);
			break;
		case ID_IP:  /* Deprecated. */
			BKE_ipo_free((Ipo *)id);
			break;
		case ID_KE:
			BKE_key_free((Key *)id);
			break;
		case ID_WO:
			BKE_world_free((World *)id);
			break;
		case ID_SCR:
			BKE_screen_free((bScreen *)id);
			break;
		case ID_VF:
			BKE_vfont_free((VFont *)id);
			break;
		case ID_TXT:
			BKE_text_free((Text *)id);
			break;
		case ID_SPK:
			BKE_speaker_free((Speaker *)id);
			break;
		case ID_SO:
			BKE_sound_free((bSound *)id);
			break;
		case ID_GR:
			BKE_group_free((Group *)id);
			break;
		case ID_AR:
			BKE_armature_free((bArmature *)id);
			break;
		case ID_AC:
			BKE_action_free((bAction *)id);
			break;
		case ID_NT:
			ntreeFreeTree((bNodeTree *)id);
			break;
		case ID_BR:
			BKE_brush_free((Brush *)id);
			break;
		case ID_PA:
			BKE_particlesettings_free((ParticleSettings *)id);
			break;
		case ID_WM:
			if (free_windowmanager_cb)
				free_windowmanager_cb(NULL, (wmWindowManager *)id);
			break;
		case ID_GD:
			BKE_gpencil_free((bGPdata *)id, true);
			break;
		case ID_MC:
			BKE_movieclip_free((MovieClip *)id);
			break;
		case ID_MSK:
			BKE_mask_free((Mask *)id);
			break;
		case ID_LS:
			BKE_linestyle_free((FreestyleLineStyle *)id);
			break;
		case ID_PAL:
			BKE_palette_free((Palette *)id);
			break;
		case ID_PC:
			BKE_paint_curve_free((PaintCurve *)id);
			break;
		case ID_CF:
			BKE_cachefile_free((CacheFile *)id);
			break;
	}

	/* avoid notifying on removed data */
	BKE_main_lock(bmain);

	if (free_notifier_reference_cb) {
		free_notifier_reference_cb(id);
	}

	if (remap_editor_id_reference_cb) {
		remap_editor_id_reference_cb(id, NULL);
	}

	BLI_remlink(lb, id);

	BKE_libblock_free_data(bmain, id);
	BKE_main_unlock(bmain);

	MEM_freeN(id);
}
示例#6
0
void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag)
{
	ID *id = idv;

	if (use_flag_from_idtag) {
		if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
			flag |= LIB_ID_FREE_NO_MAIN;
		}
		else {
			flag &= ~LIB_ID_FREE_NO_MAIN;
		}

		if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) {
			flag |= LIB_ID_FREE_NO_USER_REFCOUNT;
		}
		else {
			flag &= ~LIB_ID_FREE_NO_USER_REFCOUNT;
		}

		if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) {
			flag |= LIB_ID_FREE_NOT_ALLOCATED;
		}
		else {
			flag &= ~LIB_ID_FREE_NOT_ALLOCATED;
		}
	}

	BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || bmain != NULL);
	BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NOT_ALLOCATED) == 0);
	BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0);

	const short type = GS(id->name);

	if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) {
		DAG_id_type_tag(bmain, type);
	}

#ifdef WITH_PYTHON
	BPY_id_release(id);
#endif

	if ((flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0) {
		BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
	}

	BKE_libblock_free_datablock(id, flag);

	/* avoid notifying on removed data */
	if (bmain) {
		BKE_main_lock(bmain);
	}

	if ((flag & LIB_ID_FREE_NO_UI_USER) == 0) {
		if (free_notifier_reference_cb) {
			free_notifier_reference_cb(id);
		}

		if (remap_editor_id_reference_cb) {
			remap_editor_id_reference_cb(id, NULL);
		}
	}

	if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
		ListBase *lb = which_libbase(bmain, type);
		BLI_remlink(lb, id);
	}

	BKE_libblock_free_data(id, (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0);

	if (bmain) {
		BKE_main_unlock(bmain);
	}

	if ((flag & LIB_ID_FREE_NOT_ALLOCATED) == 0) {
		MEM_freeN(id);
	}
}
示例#7
0
/**
 * 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).
 */
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);

	libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data);

	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);
	}

	skipped_direct = id_remap_data.skipped_direct;
	skipped_refcounted = id_remap_data.skipped_refcounted;

	/* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually
	 * been incremented for that, we have to decrease once more its user count... unless we had to skip
	 * some 'user_one' cases. */
	if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
		id_us_clear_real(old_id);
	}

	if (old_id->us - skipped_refcounted < 0) {
		printf("Error in remapping process from '%s' (%p) to '%s' (%p): "
		       "wrong user count in old ID after process (summing up to %d)\n",
		       old_id->name, old_id, new_id ? new_id->name : "<NULL>", new_id, old_id->us - skipped_refcounted);
		BLI_assert(0);
	}

	if (skipped_direct == 0) {
		/* old_id is assumed to not be used directly anymore... */
		if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) {
			old_id->tag &= ~LIB_TAG_EXTERN;
			old_id->tag |= LIB_TAG_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?
	 */
	switch (GS(old_id->name)) {
		case ID_OB:
			libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
			break;
		case ID_GR:
			if (!new_id) {  /* Only affects us in case group was unlinked. */
				for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
					libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
				}
			}
			break;
		case ID_ME:
		case ID_CU:
		case ID_MB:
			if (new_id) {  /* Only affects us in case obdata was relinked (changed). */
				for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
					libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id);
				}
			}
			break;
		default:
			break;
	}

	/* Node trees may virtually use any kind of data-block... */
	/* XXX Yuck!!!! nodetree update can do pretty much any thing when talking about py nodes,
	 *     including creating new data-blocks (see T50385), so we need to unlock main here. :(
	 *     Why can't we have re-entrent locks? */
	BKE_main_unlock(bmain);
	libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
	BKE_main_lock(bmain);

	/* Full rebuild of DAG! */
	DAG_relations_tag_update(bmain);
}
示例#8
0
/* Does not fix anything, but checks that all linked data-blocks are still valid (i.e. pointing to the right library). */
bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports)
{
	ListBase mainlist;
	bool is_valid = true;

	BKE_main_lock(bmain);

	blo_split_main(&mainlist, bmain);

	ListBase *lbarray[MAX_LIBARRAY];
	int i = set_listbasepointers(bmain, lbarray);
	while (i--) {
		for (ID *id = lbarray[i]->first; id != NULL; id = id->next) {
			if (id->lib != NULL) {
				is_valid = false;
				BKE_reportf(reports, RPT_ERROR,
				            "ID %s is in local database while being linked from library %s!\n", id->name, id->lib->name);
			}
		}
	}

	for (Main *curmain = bmain->next; curmain != NULL; curmain = curmain->next) {
		Library *curlib = curmain->curlib;
		if (curlib == NULL) {
			BKE_reportf(reports, RPT_ERROR,
			            "Library database with NULL library datablock!\n");
			continue;
		}

		BKE_library_filepath_set(bmain, curlib, curlib->name);
		BlendHandle *bh = BLO_blendhandle_from_file(curlib->filepath, reports);

		if (bh == NULL) {
			BKE_reportf(reports, RPT_ERROR,
			            "Library ID %s not found at expected path %s!\n", curlib->id.name, curlib->filepath);
			continue;
		}

		i = set_listbasepointers(curmain, lbarray);
		while (i--) {
			ID *id = lbarray[i]->first;
			if (id == NULL) {
				continue;
			}

			if (GS(id->name) == ID_LI) {
				is_valid = false;
				BKE_reportf(reports, RPT_ERROR,
				            "Library ID %s in library %s, this should not happen!\n", id->name, curlib->name);
				continue;
			}

			int totnames = 0;
			LinkNode *names = BLO_blendhandle_get_datablock_names(bh, GS(id->name), &totnames);
			for (; id != NULL; id = id->next) {
				if (id->lib == NULL) {
					is_valid = false;
					BKE_reportf(reports, RPT_ERROR,
					            "ID %s has NULL lib pointer while being in library %s!\n", id->name, curlib->name);
					continue;
				}
				if (id->lib != curlib) {
					is_valid = false;
					BKE_reportf(reports, RPT_ERROR,
					            "ID %s has mismatched lib pointer!\n", id->name);
					continue;
				}

				LinkNode *name = names;
				for (; name; name = name->next) {
					char *str_name = (char *)name->link;
					if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) {
						break;
					}
				}

				if (name == NULL) {
					is_valid = false;
					BKE_reportf(reports, RPT_ERROR,
					            "ID %s not found in library %s anymore!\n", id->name, id->lib->name);
					continue;
				}
			}

			BLI_linklist_free(names, free);
		}

		BLO_blendhandle_close(bh);
	}

	blo_join_main(&mainlist);

	BLI_assert(BLI_listbase_is_single(&mainlist));
	BLI_assert(mainlist.first == (void *)bmain);

	BKE_main_unlock(bmain);

	return is_valid;
}