diff options
author | Bastien Montagne <b.mont29@gmail.com> | 2020-02-10 14:58:59 +0300 |
---|---|---|
committer | Bastien Montagne <b.mont29@gmail.com> | 2020-02-10 15:00:42 +0300 |
commit | 56116bbdf434b57e4d74b1112b4b8111a7c8fa9a (patch) | |
tree | 7e3d0c83711fbd9de6c76e9d86d2d30edf66a8ab /source/blender/blenkernel/intern/library_override.c | |
parent | ae863f34df870af416b4728e65d4b6eef93a4d30 (diff) |
Cleanup/refactor: Rename `BKE_library` files to `BKE_lib`.
Note that `BKE_library.h`/`library.c` were renamed to
`BKE_lib_id.h`/`lib_id.c` to avoid having a too generic name here.
Part of T72604.
Diffstat (limited to 'source/blender/blenkernel/intern/library_override.c')
-rw-r--r-- | source/blender/blenkernel/intern/library_override.c | 954 |
1 files changed, 0 insertions, 954 deletions
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c deleted file mode 100644 index a8cc37973f2..00000000000 --- a/source/blender/blenkernel/intern/library_override.c +++ /dev/null @@ -1,954 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup bke - */ - -#include <stdlib.h> -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_ID.h" -#include "DNA_object_types.h" - -#include "DEG_depsgraph.h" - -#include "BKE_armature.h" -#include "BKE_library.h" -#include "BKE_library_override.h" -#include "BKE_library_remap.h" -#include "BKE_main.h" - -#include "BLI_utildefines.h" -#include "BLI_ghash.h" -#include "BLI_listbase.h" -#include "BLI_string.h" - -#include "RNA_access.h" -#include "RNA_types.h" - -#include "PIL_time.h" -#include "PIL_time_utildefines.h" - -#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */ - -static void bke_override_property_copy(IDOverrideLibraryProperty *op_dst, - IDOverrideLibraryProperty *op_src); -static void bke_override_property_operation_copy(IDOverrideLibraryPropertyOperation *opop_dst, - IDOverrideLibraryPropertyOperation *opop_src); - -static void bke_override_property_clear(IDOverrideLibraryProperty *op); -static void bke_override_property_operation_clear(IDOverrideLibraryPropertyOperation *opop); - -/* Temp, for until library override is ready and tested enough to go 'public', - * we hide it by default in UI and such. */ -static bool _override_library_enabled = true; - -void BKE_override_library_enable(const bool do_enable) -{ - _override_library_enabled = do_enable; -} - -bool BKE_override_library_is_enabled() -{ - return _override_library_enabled; -} - -/** Initialize empty overriding of \a reference_id by \a local_id. */ -IDOverrideLibrary *BKE_override_library_init(ID *local_id, ID *reference_id) -{ - /* If reference_id is NULL, we are creating an override template for purely local data. - * Else, reference *must* be linked data. */ - BLI_assert(reference_id == NULL || reference_id->lib != NULL); - BLI_assert(local_id->override_library == NULL); - - ID *ancestor_id; - for (ancestor_id = reference_id; ancestor_id != NULL && ancestor_id->override_library != NULL && - ancestor_id->override_library->reference != NULL; - ancestor_id = ancestor_id->override_library->reference) { - /* pass */ - } - - if (ancestor_id != NULL && ancestor_id->override_library != NULL) { - /* Original ID has a template, use it! */ - BKE_override_library_copy(local_id, ancestor_id); - if (local_id->override_library->reference != reference_id) { - id_us_min(local_id->override_library->reference); - local_id->override_library->reference = reference_id; - id_us_plus(local_id->override_library->reference); - } - return local_id->override_library; - } - - /* Else, generate new empty override. */ - local_id->override_library = MEM_callocN(sizeof(*local_id->override_library), __func__); - local_id->override_library->reference = reference_id; - id_us_plus(local_id->override_library->reference); - local_id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK; - /* TODO do we want to add tag or flag to referee to mark it as such? */ - return local_id->override_library; -} - -/** Deep copy of a whole override from \a src_id to \a dst_id. */ -void BKE_override_library_copy(ID *dst_id, const ID *src_id) -{ - BLI_assert(src_id->override_library != NULL); - - if (dst_id->override_library != NULL) { - if (src_id->override_library == NULL) { - BKE_override_library_free(&dst_id->override_library, true); - return; - } - else { - BKE_override_library_clear(dst_id->override_library, true); - } - } - else if (src_id->override_library == NULL) { - return; - } - else { - BKE_override_library_init(dst_id, NULL); - } - - /* Source is already overriding data, we copy it but reuse its reference for dest ID. - * otherwise, source is only an override template, it then becomes reference of dest ID. */ - dst_id->override_library->reference = src_id->override_library->reference ? - src_id->override_library->reference : - (ID *)src_id; - id_us_plus(dst_id->override_library->reference); - - BLI_duplicatelist(&dst_id->override_library->properties, &src_id->override_library->properties); - for (IDOverrideLibraryProperty *op_dst = dst_id->override_library->properties.first, - *op_src = src_id->override_library->properties.first; - op_dst; - op_dst = op_dst->next, op_src = op_src->next) { - bke_override_property_copy(op_dst, op_src); - } - - dst_id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK; -} - -/** Clear any overriding data from given \a override. */ -void BKE_override_library_clear(IDOverrideLibrary *override, const bool do_id_user) -{ - BLI_assert(override != NULL); - - if (override->runtime != NULL) { - BLI_ghash_clear(override->runtime, NULL, NULL); - } - - for (IDOverrideLibraryProperty *op = override->properties.first; op; op = op->next) { - bke_override_property_clear(op); - } - BLI_freelistN(&override->properties); - - if (do_id_user) { - id_us_min(override->reference); - /* override->storage should never be refcounted... */ - } -} - -/** Free given \a override. */ -void BKE_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user) -{ - BLI_assert(*override != NULL); - - if ((*override)->runtime != NULL) { - BLI_ghash_free((*override)->runtime, NULL, NULL); - (*override)->runtime = NULL; - } - - BKE_override_library_clear(*override, do_id_user); - MEM_freeN(*override); - *override = NULL; -} - -static ID *override_library_create_from(Main *bmain, ID *reference_id) -{ - ID *local_id; - - if (!BKE_id_copy(bmain, reference_id, (ID **)&local_id)) { - return NULL; - } - id_us_min(local_id); - - BKE_override_library_init(local_id, reference_id); - local_id->override_library->flag |= OVERRIDE_LIBRARY_AUTO; - - return local_id; -} - -/** Create an overridden local copy of linked reference. */ -ID *BKE_override_library_create_from_id(Main *bmain, ID *reference_id, const bool do_tagged_remap) -{ - BLI_assert(reference_id != NULL); - BLI_assert(reference_id->lib != NULL); - - ID *local_id = override_library_create_from(bmain, reference_id); - - if (do_tagged_remap) { - ID *other_id; - FOREACH_MAIN_ID_BEGIN (bmain, other_id) { - if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) { - /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap - * local IDs usages anyway... */ - BKE_libblock_relink_ex(bmain, - other_id, - reference_id, - local_id, - ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); - } - } - FOREACH_MAIN_ID_END; - } - - return local_id; -} - -/** - * 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. - * - * \return \a true on success, \a false otherwise. - */ -bool BKE_override_library_create_from_tag(Main *bmain) -{ - ID *reference_id; - bool ret = true; - - ListBase todo_ids = {NULL}; - LinkData *todo_id_iter; - - /* Get all IDs we want to override. */ - FOREACH_MAIN_ID_BEGIN (bmain, reference_id) { - if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) { - todo_id_iter = MEM_callocN(sizeof(*todo_id_iter), __func__); - todo_id_iter->data = reference_id; - BLI_addtail(&todo_ids, todo_id_iter); - } - } - FOREACH_MAIN_ID_END; - - /* Override the IDs. */ - for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { - reference_id = todo_id_iter->data; - if ((reference_id->newid = override_library_create_from(bmain, reference_id)) == NULL) { - ret = false; - } - else { - /* We also tag the new IDs so that in next step we can remap their pointers too. */ - reference_id->newid->tag |= LIB_TAG_DOIT; - } - } - - /* Only remap new local ID's pointers, we don't want to force our new overrides onto our whole - * existing linked IDs usages. */ - for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { - ID *other_id; - reference_id = todo_id_iter->data; - - if (reference_id->newid == NULL) { - continue; - } - - /* Still checking the whole Main, that way we can tag other local IDs as needing to be remapped - * to use newly created overriding IDs, if needed. */ - FOREACH_MAIN_ID_BEGIN (bmain, other_id) { - if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) { - ID *local_id = reference_id->newid; - /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap - * local IDs usages anyway... */ - BKE_libblock_relink_ex(bmain, - other_id, - reference_id, - local_id, - ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); - } - } - FOREACH_MAIN_ID_END; - } - - BLI_freelistN(&todo_ids); - - return ret; -} - -/* We only build override GHash on request. */ -BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_mapping_ensure( - IDOverrideLibrary *override) -{ - if (override->runtime == NULL) { - override->runtime = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); - for (IDOverrideLibraryProperty *op = override->properties.first; op != NULL; op = op->next) { - BLI_ghash_insert(override->runtime, op->rna_path, op); - } - } - - return override->runtime; -} - -/** - * Find override property from given RNA path, if it exists. - */ -IDOverrideLibraryProperty *BKE_override_library_property_find(IDOverrideLibrary *override, - const char *rna_path) -{ - IDOverrideLibraryRuntime *override_runtime = override_library_rna_path_mapping_ensure(override); - return BLI_ghash_lookup(override_runtime, rna_path); -} - -/** - * Find override property from given RNA path, or create it if it does not exist. - */ -IDOverrideLibraryProperty *BKE_override_library_property_get(IDOverrideLibrary *override, - const char *rna_path, - bool *r_created) -{ - IDOverrideLibraryProperty *op = BKE_override_library_property_find(override, rna_path); - - if (op == NULL) { - op = MEM_callocN(sizeof(IDOverrideLibraryProperty), __func__); - op->rna_path = BLI_strdup(rna_path); - BLI_addtail(&override->properties, op); - - IDOverrideLibraryRuntime *override_runtime = override_library_rna_path_mapping_ensure( - override); - BLI_ghash_insert(override_runtime, op->rna_path, op); - - if (r_created) { - *r_created = true; - } - } - else if (r_created) { - *r_created = false; - } - - return op; -} - -void bke_override_property_copy(IDOverrideLibraryProperty *op_dst, - IDOverrideLibraryProperty *op_src) -{ - op_dst->rna_path = BLI_strdup(op_src->rna_path); - BLI_duplicatelist(&op_dst->operations, &op_src->operations); - - for (IDOverrideLibraryPropertyOperation *opop_dst = op_dst->operations.first, - *opop_src = op_src->operations.first; - opop_dst; - opop_dst = opop_dst->next, opop_src = opop_src->next) { - bke_override_property_operation_copy(opop_dst, opop_src); - } -} - -void bke_override_property_clear(IDOverrideLibraryProperty *op) -{ - BLI_assert(op->rna_path != NULL); - - MEM_freeN(op->rna_path); - - for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { - bke_override_property_operation_clear(opop); - } - BLI_freelistN(&op->operations); -} - -/** - * Remove and free given \a override_property from given ID \a override. - */ -void BKE_override_library_property_delete(IDOverrideLibrary *override, - IDOverrideLibraryProperty *override_property) -{ - bke_override_property_clear(override_property); - if (override->runtime != NULL) { - BLI_ghash_remove(override->runtime, override_property->rna_path, NULL, NULL); - } - BLI_freelinkN(&override->properties, override_property); -} - -/** - * Find override property operation from given sub-item(s), if it exists. - */ -IDOverrideLibraryPropertyOperation *BKE_override_library_property_operation_find( - IDOverrideLibraryProperty *override_property, - const char *subitem_refname, - const char *subitem_locname, - const int subitem_refindex, - const int subitem_locindex, - const bool strict, - bool *r_strict) -{ - IDOverrideLibraryPropertyOperation *opop; - const int subitem_defindex = -1; - - if (r_strict) { - *r_strict = true; - } - - if (subitem_locname != NULL) { - opop = BLI_findstring_ptr(&override_property->operations, - subitem_locname, - offsetof(IDOverrideLibraryPropertyOperation, subitem_local_name)); - - if (opop == NULL) { - return NULL; - } - - if (subitem_refname == NULL || opop->subitem_reference_name == NULL) { - return subitem_refname == opop->subitem_reference_name ? opop : NULL; - } - return (subitem_refname != NULL && opop->subitem_reference_name != NULL && - STREQ(subitem_refname, opop->subitem_reference_name)) ? - opop : - NULL; - } - - if (subitem_refname != NULL) { - opop = BLI_findstring_ptr( - &override_property->operations, - subitem_refname, - offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_name)); - - if (opop == NULL) { - return NULL; - } - - if (subitem_locname == NULL || opop->subitem_local_name == NULL) { - return subitem_locname == opop->subitem_local_name ? opop : NULL; - } - return (subitem_locname != NULL && opop->subitem_local_name != NULL && - STREQ(subitem_locname, opop->subitem_local_name)) ? - opop : - NULL; - } - - if ((opop = BLI_listbase_bytes_find( - &override_property->operations, - &subitem_locindex, - sizeof(subitem_locindex), - offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index)))) { - return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL; - } - - if ((opop = BLI_listbase_bytes_find( - &override_property->operations, - &subitem_refindex, - sizeof(subitem_refindex), - offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_index)))) { - return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL; - } - - /* index == -1 means all indices, that is valid fallback in case we requested specific index. */ - if (!strict && (subitem_locindex != subitem_defindex) && - (opop = BLI_listbase_bytes_find( - &override_property->operations, - &subitem_defindex, - sizeof(subitem_defindex), - offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index)))) { - if (r_strict) { - *r_strict = false; - } - return opop; - } - - return NULL; -} - -/** - * Find override property operation from given sub-item(s), or create it if it does not exist. - */ -IDOverrideLibraryPropertyOperation *BKE_override_library_property_operation_get( - IDOverrideLibraryProperty *override_property, - const short operation, - const char *subitem_refname, - const char *subitem_locname, - const int subitem_refindex, - const int subitem_locindex, - const bool strict, - bool *r_strict, - bool *r_created) -{ - IDOverrideLibraryPropertyOperation *opop = BKE_override_library_property_operation_find( - override_property, - subitem_refname, - subitem_locname, - subitem_refindex, - subitem_locindex, - strict, - r_strict); - - if (opop == NULL) { - opop = MEM_callocN(sizeof(IDOverrideLibraryPropertyOperation), __func__); - opop->operation = operation; - if (subitem_locname) { - opop->subitem_local_name = BLI_strdup(subitem_locname); - } - if (subitem_refname) { - opop->subitem_reference_name = BLI_strdup(subitem_refname); - } - opop->subitem_local_index = subitem_locindex; - opop->subitem_reference_index = subitem_refindex; - - BLI_addtail(&override_property->operations, opop); - - if (r_created) { - *r_created = true; - } - } - else if (r_created) { - *r_created = false; - } - - return opop; -} - -void bke_override_property_operation_copy(IDOverrideLibraryPropertyOperation *opop_dst, - IDOverrideLibraryPropertyOperation *opop_src) -{ - if (opop_src->subitem_reference_name) { - opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name); - } - if (opop_src->subitem_local_name) { - opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name); - } -} - -void bke_override_property_operation_clear(IDOverrideLibraryPropertyOperation *opop) -{ - if (opop->subitem_reference_name) { - MEM_freeN(opop->subitem_reference_name); - } - if (opop->subitem_local_name) { - MEM_freeN(opop->subitem_local_name); - } -} - -/** - * Remove and free given \a override_property_operation from given ID \a override_property. - */ -void BKE_override_library_property_operation_delete( - IDOverrideLibraryProperty *override_property, - IDOverrideLibraryPropertyOperation *override_property_operation) -{ - bke_override_property_operation_clear(override_property_operation); - BLI_freelinkN(&override_property->operations, override_property_operation); -} - -/** - * 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_override_library_status_check_local(Main *bmain, ID *local) -{ - BLI_assert(local->override_library != NULL); - - ID *reference = local->override_library->reference; - - if (reference == NULL) { - /* This is an override template, local status is always OK! */ - return true; - } - - BLI_assert(GS(local->name) == GS(reference->name)); - - if (GS(local->name) == ID_OB) { - /* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would ensure - * this is valid, but in some cases (like hidden collections etc.) this won't be the case, so - * we need to take care of this ourselves. */ - Object *ob_local = (Object *)local; - if (ob_local->data != NULL && ob_local->type == OB_ARMATURE && ob_local->pose != NULL && - ob_local->pose->flag & POSE_RECALC) { - BKE_pose_rebuild(bmain, ob_local, ob_local->data, true); - } - } - - /* Note that reference is assumed always valid, caller has to ensure that itself. */ - - PointerRNA rnaptr_local, rnaptr_reference; - RNA_id_pointer_create(local, &rnaptr_local); - RNA_id_pointer_create(reference, &rnaptr_reference); - - if (!RNA_struct_override_matches(bmain, - &rnaptr_local, - &rnaptr_reference, - NULL, - local->override_library, - RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | - RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, - NULL)) { - local->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK; - return false; - } - - return true; -} - -/** - * 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_override_library_status_check_reference(Main *bmain, ID *local) -{ - BLI_assert(local->override_library != NULL); - - ID *reference = local->override_library->reference; - - if (reference == NULL) { - /* This is an override template, reference is virtual, so its status is always OK! */ - return true; - } - - BLI_assert(GS(local->name) == GS(reference->name)); - - if (reference->override_library && (reference->tag & LIB_TAG_OVERRIDE_LIBRARY_REFOK) == 0) { - if (!BKE_override_library_status_check_reference(bmain, reference)) { - /* If reference is also override of another data-block, and its status is not OK, - * then this override is not OK either. - * Note that this should only happen when reloading libraries... */ - local->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK; - return false; - } - } - - if (GS(local->name) == ID_OB) { - /* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would ensure - * this is valid, but in some cases (like hidden collections etc.) this won't be the case, so - * we need to take care of this ourselves. */ - Object *ob_local = (Object *)local; - if (ob_local->data != NULL && ob_local->type == OB_ARMATURE && ob_local->pose != NULL && - ob_local->pose->flag & POSE_RECALC) { - BKE_pose_rebuild(bmain, ob_local, ob_local->data, true); - } - } - - PointerRNA rnaptr_local, rnaptr_reference; - RNA_id_pointer_create(local, &rnaptr_local); - RNA_id_pointer_create(reference, &rnaptr_reference); - - if (!RNA_struct_override_matches(bmain, - &rnaptr_local, - &rnaptr_reference, - NULL, - local->override_library, - RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, - NULL)) { - local->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK; - return false; - } - - return true; -} - -/** - * Compares 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 diff values and applying overrides are much cheaper. - * - * \return true if new overriding op was created, or some local data was reset. */ -bool BKE_override_library_operations_create(Main *bmain, ID *local, const bool force_auto) -{ - BLI_assert(local->override_library != NULL); - const bool is_template = (local->override_library->reference == NULL); - bool ret = false; - - if (!is_template && (force_auto || local->override_library->flag & OVERRIDE_LIBRARY_AUTO)) { - /* Do not attempt to generate overriding rules from an empty place-holder generated by link - * code when it cannot find to actual library/ID. Much better to keep the local datablock as - * is in the file in that case, until broken lib is fixed. */ - if (ID_MISSING(local->override_library->reference)) { - return ret; - } - - if (GS(local->name) == ID_OB) { - /* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would ensure - * this is valid, but in some cases (like hidden collections etc.) this won't be the case, so - * we need to take care of this ourselves. */ - Object *ob_local = (Object *)local; - if (ob_local->data != NULL && ob_local->type == OB_ARMATURE && ob_local->pose != NULL && - ob_local->pose->flag & POSE_RECALC) { - BKE_pose_rebuild(bmain, ob_local, ob_local->data, true); - } - } - - PointerRNA rnaptr_local, rnaptr_reference; - RNA_id_pointer_create(local, &rnaptr_local); - RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference); - - eRNAOverrideMatchResult report_flags = 0; - RNA_struct_override_matches(bmain, - &rnaptr_local, - &rnaptr_reference, - NULL, - local->override_library, - RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, - &report_flags); - if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) { - ret = true; - } -#ifndef NDEBUG - if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) { - printf("We did restore some properties of %s from its reference.\n", local->name); - } - if (ret) { - printf("We did generate library override rules for %s\n", local->name); - } - else { - printf("No new library override rules for %s\n", local->name); - } -#endif - } - return ret; -} - -/** Check all overrides from given \a bmain and create/update overriding operations as needed. */ -void BKE_main_override_library_operations_create(Main *bmain, const bool force_auto) -{ - ID *id; - - FOREACH_MAIN_ID_BEGIN (bmain, id) { - if ((ID_IS_OVERRIDE_LIBRARY(id) && force_auto) || - (ID_IS_OVERRIDE_LIBRARY_AUTO(id) && (id->tag & LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH))) { - BKE_override_library_operations_create(bmain, id, force_auto); - id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH; - } - } - FOREACH_MAIN_ID_END; -} - -/** Update given override from its reference (re-applying overridden properties). */ -void BKE_override_library_update(Main *bmain, ID *local) -{ - if (local->override_library == NULL || local->override_library->reference == NULL) { - return; - } - - /* Do not attempt to apply overriding rules over an empty place-holder generated by link code - * when it cannot find to actual library/ID. Much better to keep the local datablock as loaded - * from the file in that case, until broken lib is fixed. */ - if (ID_MISSING(local->override_library->reference)) { - return; - } - - /* Recursively do 'ancestors' overrides first, if any. */ - if (local->override_library->reference->override_library && - (local->override_library->reference->tag & LIB_TAG_OVERRIDE_LIBRARY_REFOK) == 0) { - BKE_override_library_update(bmain, local->override_library->reference); - } - - /* We want to avoid having to remap here, however creating up-to-date override is much simpler - * if based on reference than on current override. - * So we work on temp copy of reference, and 'swap' its content with local. */ - - /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)! - * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will - * do, as inn-efficient as it is. :/ - * Actually, maybe not! Since we are swapping with original ID's local content, we want to - * keep user-count in correct state when freeing tmp_id - * (and that user-counts of IDs used by 'new' local data also remain correct). */ - /* This would imply change in handling of user-count all over RNA - * (and possibly all over Blender code). - * Not impossible to do, but would rather see first if extra useless usual user handling - * is actually a (performances) issue here. */ - - ID *tmp_id; - BKE_id_copy(bmain, local->override_library->reference, &tmp_id); - - if (tmp_id == NULL) { - return; - } - - PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL; - RNA_id_pointer_create(local, &rnaptr_src); - RNA_id_pointer_create(tmp_id, &rnaptr_dst); - if (local->override_library->storage) { - rnaptr_storage = &rnaptr_storage_stack; - RNA_id_pointer_create(local->override_library->storage, rnaptr_storage); - } - - RNA_struct_override_apply( - bmain, &rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_library); - - /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. - * So when we'll free tmp_id, we'll actually free old, outdated data from local. */ - BKE_id_swap(bmain, local, tmp_id); - - /* Again, horribly inn-efficient in our case, we need something off-Main - * (aka more generic nolib copy/free stuff)! */ - /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */ - BKE_id_free_ex(bmain, tmp_id, LIB_ID_FREE_NO_UI_USER, true); - - if (local->override_library->storage) { - /* We know this datablock is not used anywhere besides local->override->storage. */ - /* XXX For until we get fully shadow copies, we still need to ensure storage releases - * its usage of any ID pointers it may have. */ - BKE_id_free_ex(bmain, local->override_library->storage, LIB_ID_FREE_NO_UI_USER, true); - local->override_library->storage = NULL; - } - - local->tag |= LIB_TAG_OVERRIDE_LIBRARY_REFOK; - - /* Full rebuild of Depsgraph! */ - - /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */ - DEG_on_visible_update(bmain, true); -} - -/** Update all overrides from given \a bmain. */ -void BKE_main_override_library_update(Main *bmain) -{ - ID *id; - - FOREACH_MAIN_ID_BEGIN (bmain, id) { - if (id->override_library != NULL && id->lib == NULL) { - BKE_override_library_update(bmain, id); - } - } - FOREACH_MAIN_ID_END; -} - -/** - * Storage (how to store overriding data into `.blend` files). - * - * Basically: - * 1) Only 'differential' storage needs special handling here. All others (replacing values or - * inserting/removing items from a collection) can be handled with simply storing current - * content of local data-block. - * 2) We store the differential value into a second 'ghost' data-block, - * which is an empty ID of same type as local one, - * where we only define values that need differential data. - * - * This avoids us having to modify 'real' data-block at write time (and restoring it afterwards), - * which is inefficient, and potentially dangerous (in case of concurrent access...), while not - * using much extra memory in typical cases. It also ensures stored data-block always contains - * exact same data as "desired" ones (kind of "baked" data-blocks). - */ - -/** Initialize an override storage. */ -OverrideLibraryStorage *BKE_override_library_operations_store_initialize(void) -{ - return BKE_main_new(); -} - -/** - * 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. */ -ID *BKE_override_library_operations_store_start(Main *bmain, - OverrideLibraryStorage *override_storage, - ID *local) -{ - BLI_assert(local->override_library != NULL); - BLI_assert(override_storage != NULL); - const bool is_template = (local->override_library->reference == NULL); - - if (is_template) { - /* This is actually purely local data with an override template, nothing to do here! */ - return NULL; - } - - /* Forcefully ensure we know about all needed override operations. */ - BKE_override_library_operations_create(bmain, local, false); - - ID *storage_id; -#ifdef DEBUG_OVERRIDE_TIMEIT - TIMEIT_START_AVERAGED(BKE_override_operations_store_start); -#endif - - /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy - * never-overridable data (like Mesh geometry etc.)? And also maybe avoid lib reference-counting - * completely (shallow copy...). */ - /* This would imply change in handling of user-count all over RNA - * (and possibly all over Blender code). - * Not impossible to do, but would rather see first is extra useless usual user handling is - * actually a (performances) issue here, before doing it. */ - BKE_id_copy((Main *)override_storage, local, &storage_id); - - if (storage_id != NULL) { - PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage; - RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference); - RNA_id_pointer_create(local, &rnaptr_final); - RNA_id_pointer_create(storage_id, &rnaptr_storage); - - if (!RNA_struct_override_store( - bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_library)) { - BKE_id_free_ex(override_storage, storage_id, LIB_ID_FREE_NO_UI_USER, true); - storage_id = NULL; - } - } - - local->override_library->storage = storage_id; - -#ifdef DEBUG_OVERRIDE_TIMEIT - TIMEIT_END_AVERAGED(BKE_override_operations_store_start); -#endif - return storage_id; -} - -/** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */ -void BKE_override_library_operations_store_end(OverrideLibraryStorage *UNUSED(override_storage), - ID *local) -{ - BLI_assert(local->override_library != NULL); - - /* Nothing else to do here really, we need to keep all temp override storage data-blocks in - * memory until whole file is written anyway (otherwise we'd get mem pointers overlap...). */ - local->override_library->storage = NULL; -} - -void BKE_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage) -{ - /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' - * copies of IDs without increasing usercount of used data-blocks. */ - ID *id; - - FOREACH_MAIN_ID_BEGIN (override_storage, id) { - BKE_id_free_ex(override_storage, id, LIB_ID_FREE_NO_UI_USER, true); - } - FOREACH_MAIN_ID_END; - - BKE_main_free(override_storage); -} |