Merge branch 'blender-v3.3-release'

Conflicts:
	source/blender/blenkernel/BKE_lib_override.h
This commit is contained in:
Bastien Montagne 2022-08-12 12:40:46 +02:00
commit 74645d969b
15 changed files with 602 additions and 48 deletions

View File

@ -85,7 +85,11 @@ typedef void (*IDTypeForeachCacheFunction)(struct ID *id,
typedef void (*IDTypeForeachPathFunction)(struct ID *id, struct BPathForeachPathData *bpath_data);
typedef struct ID *(*IDTypeEmbeddedOwnerGetFunction)(struct Main *bmain, struct ID *id);
/** \param owner_id_hint: If non-NULL, a potential owner of the given embedded ID. Can speed up
* look-up of the owner ID in some cases. */
typedef struct ID *(*IDTypeEmbeddedOwnerGetFunction)(struct Main *bmain,
struct ID *id,
struct ID *owner_id_hint);
typedef void (*IDTypeBlendWriteFunction)(struct BlendWriter *writer,
struct ID *id,

View File

@ -60,16 +60,18 @@ void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, bool do_
void BKE_lib_override_library_free(struct IDOverrideLibrary **override, bool do_id_user);
/**
* Return the actual #IDOverrideLibrary data 'controlling' the given `id`, and the actual ID owning
* Return the actual #IDOverrideLibrary data 'controlling' the given `id`, and the acutal ID owning
* it.
*
* \note This is especially useful when `id` is a non-real override (e.g. embedded ID like a master
* collection or root node tree, or a shape key).
*
* \param r_owner_id: If given, will be set with the actual ID owning the return liboverride data.
* \param owner_id_hint If not NULL, a potential owner for the given override-embedded `id`.
* \param r_owner_id If given, will be set with the actual ID owning the return liboverride data.
*/
IDOverrideLibrary *BKE_lib_override_library_get(struct Main *bmain,
struct ID *id,
struct ID *owner_id_hint,
struct ID **r_owner_id);
/**

View File

@ -0,0 +1,510 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2016 Blender Foundation. All rights reserved. */
#pragma once
/** \file
* \ingroup bke
*
* API to manage data-blocks inside of Blender's Main data-base, or as independent runtime-only
* data.
*
* \note `BKE_lib_` files are for operations over data-blocks themselves, although they might
* alter Main as well (when creating/renaming/deleting an ID e.g.).
*
* \section Function Names
*
* \warning Descriptions below is ideal goal, current status of naming does not yet fully follow it
* (this is WIP).
*
* - `BKE_lib_override_library_` should be used for function affecting a single ID.
* - `BKE_lib_override_library_main_` should be used for function affecting the whole collection
* of IDs in a given Main data-base.
*/
#ifdef __cplusplus
extern "C" {
#endif
struct BlendFileReadReport;
struct Collection;
struct ID;
struct IDOverrideLibrary;
struct IDOverrideLibraryProperty;
struct IDOverrideLibraryPropertyOperation;
struct Library;
struct Main;
struct Object;
struct PointerRNA;
struct PropertyRNA;
struct ReportList;
struct Scene;
struct ViewLayer;
/**
* Initialize empty overriding of \a reference_id by \a local_id.
*/
struct IDOverrideLibrary *BKE_lib_override_library_init(struct ID *local_id,
struct ID *reference_id);
/**
* Shallow or deep copy of a whole override from \a src_id to \a dst_id.
*/
void BKE_lib_override_library_copy(struct ID *dst_id, const struct ID *src_id, bool do_full_copy);
/**
* Clear any overriding data from given \a override.
*/
void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, bool do_id_user);
/**
* Free given \a override.
*/
void BKE_lib_override_library_free(struct IDOverrideLibrary **override, bool do_id_user);
/**
* Return the actual #IDOverrideLibrary data 'controlling' the given `id`, and the actual ID owning
* it.
*
* \note This is especially useful when `id` is a non-real override (e.g. embedded ID like a master
* collection or root node tree, or a shape key).
*
<<<<<<< HEAD
* \param r_owner_id: If given, will be set with the actual ID owning the return liboverride data.
=======
* \param owner_id_hint If not NULL, a potential owner for the given override-embedded `id`.
* \param r_owner_id If given, will be set with the actual ID owning the return liboverride data.
>>>>>>> blender-v3.3-release
*/
IDOverrideLibrary *BKE_lib_override_library_get(struct Main *bmain,
struct ID *id,
struct ID *owner_id_hint,
struct ID **r_owner_id);
/**
* Check if given ID has some override rules that actually indicate the user edited it.
*/
bool BKE_lib_override_library_is_user_edited(const struct ID *id);
/**
* Check if given ID is a system override.
*/
bool BKE_lib_override_library_is_system_defined(const struct Main *bmain, const struct ID *id);
/**
* Check if given Override Property for given ID is animated (through a F-Curve in an Action, or
* from a driver).
*
* \param override_rna_prop: if not NULL, the RNA property matching the given path in the
* `override_prop`.
* \param rnaprop_index: Array in the RNA property, 0 if unknown or irrelevant.
*/
bool BKE_lib_override_library_property_is_animated(const ID *id,
const IDOverrideLibraryProperty *override_prop,
const struct PropertyRNA *override_rna_prop,
const int rnaprop_index);
/**
* Check if given ID is a leaf in its liboverride hierarchy (i.e. if it does not use any other
* override ID).
*
* NOTE: Embedded IDs of override IDs are not considered as leaves.
*/
bool BKE_lib_override_library_is_hierarchy_leaf(struct Main *bmain, struct ID *id);
/**
* Create an overridden local copy of linked reference.
*
* \note This function is very basic, low-level. It does not consider any hierarchical dependency,
* and also prevents any automatic re-sync of this local override.
*/
struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
struct ID *reference_id,
bool do_tagged_remap);
/**
* Create overridden local copies of all tagged data-blocks in given Main.
*
* \note Set `id->newid` of overridden libs with newly created overrides,
* caller is responsible to clean those pointers before/after usage as needed.
*
* \note By default, it will only remap newly created local overriding data-blocks between
* themselves, to avoid 'enforcing' those overrides into all other usages of the linked data in
* main. You can add more local IDs to be remapped to use new overriding ones by setting their
* LIB_TAG_DOIT tag.
*
* \param owner_library: the library in which the overrides should be created. Besides versioning
* and resync code path, this should always be NULL (i.e. the local .blend file).
*
* \param id_root_reference: the linked ID that is considered as the root of the overridden
* hierarchy.
*
* \param id_hierarchy_root: the override ID that is the root of the hierarchy. May be NULL, in
* which case it is assumed that the given `id_root_reference` is tagged for override, and its
* newly created override will be used as hierarchy root. Must be NULL if
* `id_hierarchy_root_reference` is not NULL.
*
* \param id_hierarchy_root_reference: the linked ID that is the root of the hierarchy. Must be
* tagged for override. May be NULL, in which case it is assumed that the given `id_root_reference`
* is tagged for override, and its newly created override will be used as hierarchy root. Must be
* NULL if `id_hierarchy_root` is not NULL.
*
* \param do_no_main: Create the new override data outside of Main database.
* Used for resyncing of linked overrides.
*
* \param do_fully_editable: if true, tag all created overrides as user-editable by default.
*
* \return \a true on success, \a false otherwise.
*/
bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
struct Library *owner_library,
const struct ID *id_root_reference,
struct ID *id_hierarchy_root,
const struct ID *id_hierarchy_root_reference,
bool do_no_main,
const bool do_fully_editable);
/**
* Advanced 'smart' function to create fully functional overrides.
*
* \note Currently it only does special things if given \a id_root is an object or collection, more
* specific behaviors may be added in the future for other ID types.
*
* \note It will override all IDs tagged with \a LIB_TAG_DOIT, and it does not clear that tag at
* its beginning, so caller code can add extra data-blocks to be overridden as well.
*
* \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
* which case \a scene's master collection children hierarchy is used instead).
*
* \param owner_library: the library in which the overrides should be created. Besides versioning
* and resync code path, this should always be NULL (i.e. the local .blend file).
*
* \param id_root_reference: The linked root ID to create an override from. May be a sub-root of
* the overall hierarchy, in which case calling code is expected to have already tagged required
* 'path' of IDs leading from the given `id_hierarchy_root` to the given `id_root`.
*
* \param id_hierarchy_root_reference: The ID to be used a hierarchy root of the overrides to be
* created. Can be either the linked root ID of the whole override hierarchy, (typically the same
* as `id_root`, unless a sub-part only of the hierarchy is overridden), or the already existing
* override hierarchy root if part of the hierarchy is already overridden.
*
* \param id_instance_hint: Some ID used as hint/reference to do some post-processing after
* overrides have been created, may be NULL. Typically, the Empty object instantiating the linked
* collection we override, currently.
*
* \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
*
* \param do_fully_editable: if true, tag all created overrides as user-editable by default.
*
* \return true if override was successfully created.
*/
bool BKE_lib_override_library_create(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Library *owner_library,
struct ID *id_root_reference,
struct ID *id_hierarchy_root_reference,
struct ID *id_instance_hint,
struct ID **r_id_root_override,
const bool do_fully_editable);
/**
* Create a library override template.
*/
bool BKE_lib_override_library_template_create(struct ID *id);
/**
* Convert a given proxy object into a library override.
*
* \note This is a thin wrapper around \a BKE_lib_override_library_create, only extra work is to
* actually convert the proxy itself into an override first.
*
* \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
* which case \a scene's master collection children hierarchy is used instead).
* \return true if override was successfully created.
*/
bool BKE_lib_override_library_proxy_convert(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Object *ob_proxy);
/**
* Convert all proxy objects into library overrides.
*
* \note Only affects local proxies, linked ones are not affected.
*/
void BKE_lib_override_library_main_proxy_convert(struct Main *bmain,
struct BlendFileReadReport *reports);
/**
* Find and set the 'hierarchy root' ID pointer of all library overrides in given `bmain`.
*
* NOTE: Cannot be called from `do_versions_after_linking` as this code needs a single complete
* Main database, not a split-by-libraries one.
*/
void BKE_lib_override_library_main_hierarchy_root_ensure(struct Main *bmain);
/**
* Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked
* data, from an existing override hierarchy.
*
* \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
* which case \a scene's master collection children hierarchy is used instead).
* \param id_root: The root liboverride ID to resync from.
* \return true if override was successfully resynced.
*/
bool BKE_lib_override_library_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct ID *id_root,
struct Collection *override_resync_residual_storage,
bool do_hierarchy_enforce,
struct BlendFileReadReport *reports);
/**
* Detect and handle required resync of overrides data, when relations between reference linked IDs
* have changed.
*
* This is a fairly complex and costly operation, typically it should be called after
* #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases.
*
* This function will first detect the remaining cases requiring a resync (namely, either when an
* existing linked ID that did not require to be overridden before now would be, or when new IDs
* are added to the hierarchy).
*
* Then it will handle the resync of necessary IDs (through calls to
* #BKE_lib_override_library_resync).
*
* \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
* which case \a scene's master collection children hierarchy is used instead).
*/
void BKE_lib_override_library_main_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct BlendFileReadReport *reports);
/**
* Advanced 'smart' function to delete library overrides (including their existing override
* hierarchy) and remap their usages to their linked reference IDs.
*
* \note All IDs tagged with #LIB_TAG_DOIT will be deleted.
*
* \param id_root: The root liboverride ID to delete.
*/
void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root);
/**
* Make given ID fully local.
*
* \note Only differs from lower-level #BKE_lib_override_library_free in infamous embedded ID
* cases.
*/
void BKE_lib_override_library_make_local(struct ID *id);
/**
* Find override property from given RNA path, if it exists.
*/
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_find(
struct IDOverrideLibrary *override, const char *rna_path);
/**
* Find override property from given RNA path, or create it if it does not exist.
*/
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_get(
struct IDOverrideLibrary *override, const char *rna_path, bool *r_created);
/**
* Remove and free given \a override_property from given ID \a override.
*/
void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override,
struct IDOverrideLibraryProperty *override_property);
/**
* Get the RNA-property matching the \a library_prop override property. Used for UI to query
* additional data about the overridden property (e.g. UI name).
*
* \param idpoin: Pointer to the override ID.
* \param library_prop: The library override property to find the matching RNA property for.
* \param r_index: The RNA array flat index (i.e. flattened index in case of multi-dimensional
* array properties). See #RNA_path_resolve_full family of functions for details.
*/
bool BKE_lib_override_rna_property_find(struct PointerRNA *idpoin,
const struct IDOverrideLibraryProperty *library_prop,
struct PointerRNA *r_override_poin,
struct PropertyRNA **r_override_prop,
int *r_index);
/**
* Find override property operation from given sub-item(s), if it exists.
*/
struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find(
struct IDOverrideLibraryProperty *override_property,
const char *subitem_refname,
const char *subitem_locname,
int subitem_refindex,
int subitem_locindex,
bool strict,
bool *r_strict);
/**
* Find override property operation from given sub-item(s), or create it if it does not exist.
*/
struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get(
struct IDOverrideLibraryProperty *override_property,
short operation,
const char *subitem_refname,
const char *subitem_locname,
int subitem_refindex,
int subitem_locindex,
bool strict,
bool *r_strict,
bool *r_created);
/**
* Remove and free given \a override_property_operation from given ID \a override_property.
*/
void BKE_lib_override_library_property_operation_delete(
struct IDOverrideLibraryProperty *override_property,
struct IDOverrideLibraryPropertyOperation *override_property_operation);
/**
* Validate that required data for a given operation are available.
*/
bool BKE_lib_override_library_property_operation_operands_validate(
struct IDOverrideLibraryPropertyOperation *override_property_operation,
struct PointerRNA *ptr_dst,
struct PointerRNA *ptr_src,
struct PointerRNA *ptr_storage,
struct PropertyRNA *prop_dst,
struct PropertyRNA *prop_src,
struct PropertyRNA *prop_storage);
/**
* Check against potential \a bmain.
*/
void BKE_lib_override_library_validate(struct Main *bmain,
struct ID *id,
struct ReportList *reports);
/**
* Check against potential \a bmain.
*/
void BKE_lib_override_library_main_validate(struct Main *bmain, struct ReportList *reports);
/**
* Check that status of local data-block is still valid against current reference one.
*
* It means that all overridable, but not overridden, properties' local values must be equal to
* reference ones. Clears #LIB_TAG_OVERRIDE_OK if they do not.
*
* This is typically used to detect whether some property has been changed in local and a new
* #IDOverrideProperty (of #IDOverridePropertyOperation) has to be added.
*
* \return true if status is OK, false otherwise.
*/
bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *local);
/**
* Check that status of reference data-block is still valid against current local one.
*
* It means that all non-overridden properties' local values must be equal to reference ones.
* Clears LIB_TAG_OVERRIDE_OK if they do not.
*
* This is typically used to detect whether some reference has changed and local
* needs to be updated against it.
*
* \return true if status is OK, false otherwise.
*/
bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local);
/**
* Compare local and reference data-blocks and create new override operations as needed,
* or reset to reference values if overriding is not allowed.
*
* \note Defining override operations is only mandatory before saving a `.blend` file on disk
* (not for undo!).
* Knowing that info at runtime is only useful for UI/UX feedback.
*
* \note This is by far the biggest operation (the more time-consuming) of the three so far,
* since it has to go over all properties in depth (all overridable ones at least).
* Generating differential values and applying overrides are much cheaper.
*
* \return true if any library operation was created.
*/
bool BKE_lib_override_library_operations_create(struct Main *bmain, struct ID *local);
/**
* Check all overrides from given \a bmain and create/update overriding operations as needed.
*/
bool BKE_lib_override_library_main_operations_create(struct Main *bmain, bool force_auto);
/**
* Reset all overrides in given \a id_root, while preserving ID relations.
*
* \param do_reset_system_override: If \a true, reset the given ID as a system override one (i.e.
* non-editable).
*/
void BKE_lib_override_library_id_reset(struct Main *bmain,
struct ID *id_root,
bool do_reset_system_override);
/**
* Reset all overrides in given \a id_root and its dependencies, while preserving ID relations.
*
* \param do_reset_system_override: If \a true, reset the given ID and all of its descendants in
* the override hierarchy as system override ones (i.e. non-editable).
*/
void BKE_lib_override_library_id_hierarchy_reset(struct Main *bmain,
struct ID *id_root,
bool do_reset_system_override);
/**
* Set or clear given tag in all operations in that override property data.
*/
void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
short tag,
bool do_set);
/**
* Set or clear given tag in all properties and operations in that override data.
*/
void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
short tag,
bool do_set);
/**
* Set or clear given tag in all properties and operations in that Main's ID override data.
*/
void BKE_lib_override_library_main_tag(struct Main *bmain, short tag, bool do_set);
/**
* Remove all tagged-as-unused properties and operations from that ID override data.
*/
void BKE_lib_override_library_id_unused_cleanup(struct ID *local);
/**
* Remove all tagged-as-unused properties and operations from that Main's ID override data.
*/
void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain);
/**
* Update given override from its reference (re-applying overridden properties).
*/
void BKE_lib_override_library_update(struct Main *bmain, struct ID *local);
/**
* Update all overrides from given \a bmain.
*/
void BKE_lib_override_library_main_update(struct Main *bmain);
/**
* In case an ID is used by another liboverride ID, user may not be allowed to delete it.
*/
bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id);
/* Storage (.blend file writing) part. */
/* For now, we just use a temp main list. */
typedef struct Main OverrideLibraryStorage;
/**
* Initialize an override storage.
*/
OverrideLibraryStorage *BKE_lib_override_library_operations_store_init(void);
/**
* Generate suitable 'write' data (this only affects differential override operations).
*
* Note that \a local ID is no more modified by this call,
* all extra data are stored in its temp \a storage_id copy.
*/
struct ID *BKE_lib_override_library_operations_store_start(
struct Main *bmain, OverrideLibraryStorage *override_storage, struct ID *local);
/**
* Restore given ID modified by #BKE_lib_override_library_operations_store_start, to its
* original state.
*/
void BKE_lib_override_library_operations_store_end(OverrideLibraryStorage *override_storage,
struct ID *local);
void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage);
#ifdef __cplusplus
}
#endif

View File

@ -162,7 +162,7 @@ static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
static ID *collection_owner_get(Main *bmain, ID *id)
static ID *collection_owner_get(Main *bmain, ID *id, ID *owner_id_hint)
{
if ((id->flag & LIB_EMBEDDED_DATA) == 0) {
return id;
@ -172,6 +172,11 @@ static ID *collection_owner_get(Main *bmain, ID *id)
Collection *master_collection = (Collection *)id;
BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
if (owner_id_hint != NULL && GS(owner_id_hint->name) == ID_SCE &&
((Scene *)owner_id_hint)->master_collection == master_collection) {
return owner_id_hint;
}
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->master_collection == master_collection) {
return &scene->id;

View File

@ -91,7 +91,7 @@ static void shapekey_foreach_id(ID *id, LibraryForeachIDData *data)
BKE_LIB_FOREACHID_PROCESS_ID(data, key->from, IDWALK_CB_LOOPBACK);
}
static ID *shapekey_owner_get(Main *UNUSED(bmain), ID *id)
static ID *shapekey_owner_get(Main *UNUSED(bmain), ID *id, ID *UNUSED(owner_id_hint))
{
return ((Key *)id)->from;
}

View File

@ -94,6 +94,7 @@ BLI_INLINE void lib_override_object_posemode_transfer(ID *id_dst, ID *id_src)
/** Get override data for a given ID. Needed because of our beloved shape keys snowflake. */
BLI_INLINE const IDOverrideLibrary *BKE_lib_override_library_get(const Main *bmain,
const ID *id,
const ID *owner_id_hint,
const ID **r_owner_id)
{
if (r_owner_id != nullptr) {
@ -104,7 +105,8 @@ BLI_INLINE const IDOverrideLibrary *BKE_lib_override_library_get(const Main *bma
if (id_type->owner_get != nullptr) {
/* The #IDTypeInfo::owner_get callback should not modify the arguments, so casting away const
* is okay. */
const ID *owner_id = id_type->owner_get(const_cast<Main *>(bmain), const_cast<ID *>(id));
const ID *owner_id = id_type->owner_get(
const_cast<Main *>(bmain), const_cast<ID *>(id), const_cast<ID *>(owner_id_hint));
if (r_owner_id != nullptr) {
*r_owner_id = owner_id;
}
@ -115,13 +117,17 @@ BLI_INLINE const IDOverrideLibrary *BKE_lib_override_library_get(const Main *bma
return id->override_library;
}
IDOverrideLibrary *BKE_lib_override_library_get(Main *bmain, ID *id, ID **r_owner_id)
IDOverrideLibrary *BKE_lib_override_library_get(Main *bmain,
ID *id,
ID *owner_id_hint,
ID **r_owner_id)
{
/* Reuse the implementation of the const access function, which does not change the arguments.
* Add const explicitly to make it clear to the compiler to avoid just calling this function. */
return const_cast<IDOverrideLibrary *>(
BKE_lib_override_library_get(const_cast<const Main *>(bmain),
const_cast<const ID *>(id),
const_cast<const ID *>(owner_id_hint),
const_cast<const ID **>(r_owner_id)));
}
@ -319,7 +325,7 @@ bool BKE_lib_override_library_is_system_defined(const Main *bmain, const ID *id)
{
if (ID_IS_OVERRIDE_LIBRARY(id)) {
const ID *override_owner_id;
BKE_lib_override_library_get(bmain, id, &override_owner_id);
BKE_lib_override_library_get(bmain, id, nullptr, &override_owner_id);
return (override_owner_id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED) !=
0;
}
@ -1087,8 +1093,9 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
}
const Library *reference_lib =
BKE_lib_override_library_get(bmain, id_owner, nullptr)->reference->lib;
const ID *to_id_reference = BKE_lib_override_library_get(bmain, to_id, nullptr)->reference;
BKE_lib_override_library_get(bmain, id_owner, nullptr, nullptr)->reference->lib;
const ID *to_id_reference =
BKE_lib_override_library_get(bmain, to_id, nullptr, nullptr)->reference;
if (to_id_reference->lib != reference_lib) {
/* We do not override data-blocks from other libraries, nor do we process them. */
continue;
@ -1439,7 +1446,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
BLI_assert(id->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
ID *id_owner;
int best_level_placeholder = 0;
BKE_lib_override_library_get(bmain, id, &id_owner);
BKE_lib_override_library_get(bmain, id, nullptr, &id_owner);
return lib_override_root_find(bmain, id_owner, curr_level + 1, &best_level_placeholder);
}
/* This way we won't process again that ID, should we encounter it again through another
@ -1478,7 +1485,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
BLI_assert(id->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
ID *id_owner;
int best_level_placeholder = 0;
BKE_lib_override_library_get(bmain, best_root_id_candidate, &id_owner);
BKE_lib_override_library_get(bmain, best_root_id_candidate, nullptr, &id_owner);
best_root_id_candidate = lib_override_root_find(
bmain, id_owner, curr_level + 1, &best_level_placeholder);
}
@ -1795,7 +1802,8 @@ static bool lib_override_library_resync(Main *bmain,
/* While this should not happen in typical cases (and won't be properly supported here),
* user is free to do all kind of very bad things, including having different local
* overrides of a same linked ID in a same hierarchy. */
IDOverrideLibrary *id_override_library = BKE_lib_override_library_get(bmain, id, nullptr);
IDOverrideLibrary *id_override_library = BKE_lib_override_library_get(
bmain, id, nullptr, nullptr);
if (id_override_library->hierarchy_root != id_root->override_library->hierarchy_root) {
continue;
@ -2177,7 +2185,7 @@ static ID *lib_override_library_main_resync_root_get(Main *bmain, ID *id)
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
if (id_type->owner_get != nullptr) {
id = id_type->owner_get(bmain, id);
id = id_type->owner_get(bmain, id, nullptr);
}
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id));
}

View File

@ -713,7 +713,7 @@ static void lib_query_unused_ids_tag_recurse(Main *bmain,
/* Directly 'by-pass' to actual real ID owner. */
const IDTypeInfo *type_info_from = BKE_idtype_get_info_from_id(id_from);
BLI_assert(type_info_from->owner_get != NULL);
id_from = type_info_from->owner_get(bmain, id_from);
id_from = type_info_from->owner_get(bmain, id_from, NULL);
}
lib_query_unused_ids_tag_recurse(

View File

@ -404,7 +404,7 @@ static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data)
}
}
static ID *node_owner_get(Main *bmain, ID *id)
static ID *node_owner_get(Main *bmain, ID *id, ID *owner_id_hint)
{
if ((id->flag & LIB_EMBEDDED_DATA) == 0) {
return id;
@ -412,6 +412,12 @@ static ID *node_owner_get(Main *bmain, ID *id)
/* TODO: Sort this NO_MAIN or not for embedded node trees. See T86119. */
// BLI_assert((id->tag & LIB_TAG_NO_MAIN) == 0);
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
if (owner_id_hint != nullptr && ntreeFromID(owner_id_hint) == ntree) {
return owner_id_hint;
}
ListBase *lists[] = {&bmain->materials,
&bmain->lights,
&bmain->worlds,
@ -421,7 +427,6 @@ static ID *node_owner_get(Main *bmain, ID *id)
&bmain->simulations,
nullptr};
bNodeTree *ntree = (bNodeTree *)id;
for (int i = 0; lists[i] != nullptr; i++) {
LISTBASE_FOREACH (ID *, id_iter, lists[i]) {
if (ntreeFromID(id_iter) == ntree) {

View File

@ -21,11 +21,20 @@
typedef struct TseGroup {
TreeStoreElem **elems;
/* Index of last used #TreeStoreElem item, to speed up search for another one. */
int lastused;
/* Counter used to reduce the amount of 'rests' of `lastused` index, otherwise search for unused
* item is exponential and becomes critically slow when there are a lot of items in the group. */
int lastused_reset_count;
/* Number of items currently in use. */
int size;
/* Number of items currently allocated. */
int allocated;
} TseGroup;
/* Only allow reset of #TseGroup.lastused counter to 0 once every 1k search. */
#define TSEGROUP_LASTUSED_RESET_VALUE 10000
/* Allocate structure for TreeStoreElements;
* Most of elements in treestore have no duplicates,
* so there is no need to preallocate memory for more than one pointer */
@ -47,6 +56,7 @@ static void tse_group_add_element(TseGroup *tse_group, TreeStoreElem *elem)
sizeof(TreeStoreElem *) * tse_group->allocated);
}
tse_group->elems[tse_group->size] = elem;
tse_group->lastused = tse_group->size;
tse_group->size++;
}
@ -136,6 +146,7 @@ void BKE_outliner_treehash_clear_used(void *treehash)
GHASH_ITER (gh_iter, treehash) {
TseGroup *group = BLI_ghashIterator_getValue(&gh_iter);
group->lastused = 0;
group->lastused_reset_count = 0;
}
}
@ -157,7 +168,6 @@ void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem)
*val_p = tse_group_create();
}
group = *val_p;
group->lastused = 0;
tse_group_add_element(group, elem);
}
@ -204,7 +214,15 @@ TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash,
int offset = group->lastused;
for (int i = 0; i < size; i++, offset++) {
/* Once at the end of the array of items, in most cases it just means that all items are
* used, so only check the whole array once every TSEGROUP_LASTUSED_RESET_VALUE times. */
if (offset >= size) {
if (LIKELY(group->lastused_reset_count <= TSEGROUP_LASTUSED_RESET_VALUE)) {
group->lastused_reset_count++;
group->lastused = group->size - 1;
break;
}
group->lastused_reset_count = 0;
offset = 0;
}

View File

@ -663,7 +663,7 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
* system override with reset. */
if (!ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY(id)) {
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
BKE_lib_override_library_get(bmain, id, &id);
BKE_lib_override_library_get(bmain, id, NULL, &id);
}
if (id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED) {
id->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;

View File

@ -364,7 +364,7 @@ void outliner_collection_delete(
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id);
BLI_assert(id_type->owner_get != nullptr);
ID *scene_owner = id_type->owner_get(bmain, &parent->id);
ID *scene_owner = id_type->owner_get(bmain, &parent->id, NULL);
BLI_assert(GS(scene_owner->name) == ID_SCE);
if (ID_IS_LINKED(scene_owner) || ID_IS_OVERRIDE_LIBRARY(scene_owner)) {
skip = true;
@ -597,7 +597,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id);
BLI_assert(id_type->owner_get != nullptr);
Scene *scene_owner = (Scene *)id_type->owner_get(bmain, &parent->id);
Scene *scene_owner = (Scene *)id_type->owner_get(bmain, &parent->id, NULL);
BLI_assert(scene_owner != nullptr);
BLI_assert(GS(scene_owner->id.name) == ID_SCE);

View File

@ -15,6 +15,7 @@
#include "BLT_translation.h"
#include "BKE_lib_override.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
@ -80,6 +81,7 @@ ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &
class OverrideIDHierarchyBuilder {
SpaceOutliner &space_outliner_;
Main &bmain_;
MainIDRelations &id_relations_;
struct HierarchyBuildData {
@ -93,8 +95,10 @@ class OverrideIDHierarchyBuilder {
};
public:
OverrideIDHierarchyBuilder(SpaceOutliner &space_outliner, MainIDRelations &id_relations)
: space_outliner_(space_outliner), id_relations_(id_relations)
OverrideIDHierarchyBuilder(SpaceOutliner &space_outliner,
Main &bmain,
MainIDRelations &id_relations)
: space_outliner_(space_outliner), bmain_(bmain), id_relations_(id_relations)
{
}
@ -115,7 +119,7 @@ ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main(
* returning. */
BKE_main_relations_create(bmain, 0);
OverrideIDHierarchyBuilder builder(space_outliner_, *bmain->relations);
OverrideIDHierarchyBuilder builder(space_outliner_, *bmain, *bmain->relations);
/* Keep track over which ID base elements were already added, and expand them once added. */
Map<ID_Type, TreeElement *> id_base_te_map;
@ -165,7 +169,8 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID(ID &override_root_id,
static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations,
const ID &parent_id,
FunctionRef<void(ID &)> fn);
static bool id_is_in_override_hierarchy(const ID &id,
static bool id_is_in_override_hierarchy(const Main &bmain,
const ID &id,
const ID &relationship_parent_id,
const ID &override_root_id);
@ -177,7 +182,11 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID_recursive(const ID &pare
build_data.parent_ids.add(&parent_id);
foreach_natural_hierarchy_child(id_relations_, parent_id, [&](ID &id) {
if (!id_is_in_override_hierarchy(id, parent_id, build_data.override_root_id_)) {
/* Some IDs can use themselves, early abort. */
if (&id == &parent_id) {
return;
}
if (!id_is_in_override_hierarchy(bmain_, id, parent_id, build_data.override_root_id_)) {
return;
}
@ -276,7 +285,8 @@ static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations,
}
}
static bool id_is_in_override_hierarchy(const ID &id,
static bool id_is_in_override_hierarchy(const Main &bmain,
const ID &id,
const ID &relationship_parent_id,
const ID &override_root_id)
{
@ -286,20 +296,12 @@ static bool id_is_in_override_hierarchy(const ID &id,
const ID *real_override_id = &id;
if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(&id)) {
/* This assumes that the parent ID is always the owner of the 'embedded' one, I.e. that no
* other ID directly uses the embedded one. Should be true, but the debug code adds some checks
* to validate this assumption. */
real_override_id = &relationship_parent_id;
#ifndef NDEBUG
if (GS(id.name) == ID_KE) {
const Key *key = (Key *)&id;
BLI_assert(real_override_id == key->from);
}
else {
BLI_assert((id.flag & LIB_EMBEDDED_DATA) != 0);
}
#endif
/* In many cases, `relationship_parent_id` is the owner, but not always (e.g. there can be
* drivers directly between an object and a shapekey). */
BKE_lib_override_library_get(const_cast<Main *>(&bmain),
const_cast<ID *>(&id),
const_cast<ID *>(&relationship_parent_id),
const_cast<ID **>(&real_override_id));
}
if (!ID_IS_OVERRIDE_LIBRARY(real_override_id)) {

View File

@ -50,7 +50,7 @@
#include "lineart_intern.h"
typedef struct LineartIsecSingle {
float v1[3], v2[3];
double v1[3], v2[3];
LineartTriangle *tri1, *tri2;
} LineartIsecSingle;
@ -3285,8 +3285,8 @@ static void lineart_add_isec_thread(LineartIsecThread *th,
th->array = new_array;
}
LineartIsecSingle *isec_single = &th->array[th->current];
copy_v3fl_v3db(isec_single->v1, v1);
copy_v3fl_v3db(isec_single->v2, v2);
copy_v3_v3_db(isec_single->v1, v1);
copy_v3_v3_db(isec_single->v2, v2);
isec_single->tri1 = tri1;
isec_single->tri2 = tri2;
if (tri1->target_reference > tri2->target_reference) {
@ -4582,8 +4582,8 @@ static void lineart_create_edges_from_isec_data(LineartIsecData *d)
LineartIsecSingle *is = &th->array[j];
LineartVert *v1 = v;
LineartVert *v2 = v + 1;
copy_v3db_v3fl(v1->gloc, is->v1);
copy_v3db_v3fl(v2->gloc, is->v2);
copy_v3_v3_db(v1->gloc, is->v1);
copy_v3_v3_db(v2->gloc, is->v2);
/* The intersection line has been generated only in geometry space, so we need to transform
* them as well. */
mul_v4_m4v3_db(v1->fbcoord, ld->conf.view_projection, v1->gloc);

View File

@ -940,7 +940,7 @@ ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path)
BLI_assert_msg(0, "Missing handling of embedded id type.");
return id;
}
return id_type->owner_get(bmain, id);
return id_type->owner_get(bmain, id, nullptr);
}
static char *rna_prepend_real_ID_path(Main *bmain, ID *id, char *path, ID **r_real_id)

View File

@ -1478,7 +1478,7 @@ static void rna_ImageFormatSettings_color_management_set(PointerRNA *ptr, int va
if (owner_id && GS(owner_id->name) == ID_NT) {
/* For compositing nodes, find the corresponding scene. */
const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(owner_id);
owner_id = type_info->owner_get(G_MAIN, owner_id);
owner_id = type_info->owner_get(G_MAIN, owner_id, NULL);
}
if (owner_id && GS(owner_id->name) == ID_SCE) {
BKE_image_format_color_management_copy_from_scene(imf, (Scene *)owner_id);