Merge branch 'blender-v3.0-release'
Conflicts: source/blender/blenkernel/BKE_blender_version.h source/blender/blenloader/intern/versioning_300.c
This commit is contained in:
commit
ec71054a9b
Notes:
blender-bot
2023-02-14 04:46:12 +01:00
Referenced by issue #82160, LibOverrides - Refactor how diffing of RNA collections is handled, and extend diffing possibilities.
|
@ -39,13 +39,13 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 2
|
||||
#define BLENDER_FILE_SUBVERSION 3
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
* was written with too new a version. */
|
||||
#define BLENDER_FILE_MIN_VERSION 300
|
||||
#define BLENDER_FILE_MIN_SUBVERSION 36
|
||||
#define BLENDER_FILE_MIN_SUBVERSION 42
|
||||
|
||||
/** User readable version string. */
|
||||
const char *BKE_blender_version_string(void);
|
||||
|
|
|
@ -55,6 +55,10 @@ void *BLI_listbase_bytes_find(const ListBase *listbase,
|
|||
const void *bytes,
|
||||
const size_t bytes_size,
|
||||
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
|
||||
void *BLI_listbase_string_or_index_find(const struct ListBase *listbase,
|
||||
const char *string,
|
||||
const size_t string_offset,
|
||||
const int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
|
||||
|
||||
/* find backwards */
|
||||
void *BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
|
||||
|
|
|
@ -825,6 +825,37 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first item in the list that matches the given string, or the given index as fallback.
|
||||
*
|
||||
* \note The string is only used is non-NULL and non-empty.
|
||||
*
|
||||
* \return The found item, or NULL.
|
||||
*/
|
||||
void *BLI_listbase_string_or_index_find(const ListBase *listbase,
|
||||
const char *string,
|
||||
const size_t string_offset,
|
||||
const int index)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link_at_index = NULL;
|
||||
|
||||
int index_iter;
|
||||
for (link = listbase->first, index_iter = 0; link; link = link->next, index_iter++) {
|
||||
if (string != NULL && string[0] != '\0') {
|
||||
const char *string_iter = ((const char *)link) + string_offset;
|
||||
|
||||
if (string[0] == string_iter[0] && STREQ(string, string_iter)) {
|
||||
return link;
|
||||
}
|
||||
}
|
||||
if (index_iter == index) {
|
||||
link_at_index = link;
|
||||
}
|
||||
}
|
||||
return link_at_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 0-based index of the first element of listbase which contains the specified
|
||||
* null-terminated string at the specified offset, or -1 if not found.
|
||||
|
|
|
@ -96,6 +96,64 @@ TEST(listbase, FindLinkOrIndex)
|
|||
BLI_freelistN(&lb);
|
||||
}
|
||||
|
||||
TEST(listbase, FindLinkFromStringOrPointer)
|
||||
{
|
||||
struct TestLink {
|
||||
struct TestLink *prev, *next;
|
||||
char name[64];
|
||||
const void *ptr;
|
||||
};
|
||||
|
||||
const char *const link1_name = "Link1";
|
||||
const char *const link2_name = "Link2";
|
||||
const void *const link1_ptr = nullptr;
|
||||
const void *const link2_ptr = link2_name;
|
||||
|
||||
const size_t name_offset = offsetof(struct TestLink, name);
|
||||
const size_t ptr_offset = offsetof(struct TestLink, ptr);
|
||||
|
||||
ListBase lb;
|
||||
struct TestLink *link1 = (struct TestLink *)MEM_callocN(sizeof(TestLink), "link1");
|
||||
BLI_strncpy(link1->name, link1_name, sizeof(link1->name));
|
||||
link1->ptr = link1_ptr;
|
||||
struct TestLink *link2 = (struct TestLink *)MEM_callocN(sizeof(TestLink), "link2");
|
||||
BLI_strncpy(link2->name, link2_name, sizeof(link2->name));
|
||||
link2->ptr = link2_ptr;
|
||||
|
||||
/* Empty list */
|
||||
BLI_listbase_clear(&lb);
|
||||
EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)nullptr);
|
||||
EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)nullptr);
|
||||
EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)nullptr);
|
||||
EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)nullptr);
|
||||
EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)nullptr);
|
||||
|
||||
/* One link */
|
||||
BLI_addtail(&lb, link1);
|
||||
EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)link1);
|
||||
EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)link1);
|
||||
EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)link1);
|
||||
EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)link1);
|
||||
EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)link1);
|
||||
EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, "", name_offset, 0), (void *)link1);
|
||||
EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 0), (void *)link1);
|
||||
EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 1), (void *)nullptr);
|
||||
|
||||
/* Two links */
|
||||
BLI_addtail(&lb, link2);
|
||||
EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)link1);
|
||||
EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)link1);
|
||||
EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)link1);
|
||||
EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)link1);
|
||||
EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)link1);
|
||||
EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link2_name, name_offset, 0), (void *)link2);
|
||||
EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 0), (void *)link1);
|
||||
EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 1), (void *)link2);
|
||||
EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, -1), (void *)nullptr);
|
||||
|
||||
BLI_freelistN(&lb);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Sort utilities & test */
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
@ -46,6 +48,7 @@
|
|||
#include "DNA_workspace_types.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_anim_data.h"
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_asset.h"
|
||||
|
@ -55,6 +58,7 @@
|
|||
#include "BKE_fcurve_driver.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_override.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_node.h"
|
||||
|
@ -74,6 +78,8 @@
|
|||
|
||||
#include "versioning_common.h"
|
||||
|
||||
static CLG_LogRef LOG = {"blo.readfile.doversion"};
|
||||
|
||||
static IDProperty *idproperty_find_ui_container(IDProperty *idprop_group)
|
||||
{
|
||||
LISTBASE_FOREACH (IDProperty *, prop, &idprop_group->data.group) {
|
||||
|
@ -1294,6 +1300,140 @@ static bool version_fix_seq_meta_range(Sequence *seq, void *user_data)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Those `version_liboverride_rnacollections_*` functions mimic the old, pre-3.0 code to find
|
||||
* anchor and source items in the given list of modifiers, constraints etc., using only the
|
||||
* `subitem_local` data of the override property operation.
|
||||
*
|
||||
* Then they convert it into the new, proper `subitem_reference` data for the anchor, and
|
||||
* `subitem_local` for the source.
|
||||
*
|
||||
* NOTE: Here only the stored override ID is available, unlike in the `override_apply` functions.
|
||||
*/
|
||||
|
||||
static void version_liboverride_rnacollections_insertion_object_constraints(
|
||||
ListBase *constraints, IDOverrideLibraryProperty *op)
|
||||
{
|
||||
LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
|
||||
if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
|
||||
continue;
|
||||
}
|
||||
bConstraint *constraint_anchor = BLI_listbase_string_or_index_find(constraints,
|
||||
opop->subitem_local_name,
|
||||
offsetof(bConstraint, name),
|
||||
opop->subitem_local_index);
|
||||
if (constraint_anchor == NULL || constraint_anchor->next == NULL) {
|
||||
/* Invalid case, just remove that override property operation. */
|
||||
CLOG_ERROR(&LOG, "Could not find anchor or source constraints in stored override data");
|
||||
BKE_lib_override_library_property_operation_delete(op, opop);
|
||||
continue;
|
||||
}
|
||||
bConstraint *constraint_src = constraint_anchor->next;
|
||||
opop->subitem_reference_name = opop->subitem_local_name;
|
||||
opop->subitem_local_name = BLI_strdup(constraint_src->name);
|
||||
opop->subitem_reference_index = opop->subitem_local_index;
|
||||
opop->subitem_local_index++;
|
||||
}
|
||||
}
|
||||
|
||||
static void version_liboverride_rnacollections_insertion_object(Object *object)
|
||||
{
|
||||
IDOverrideLibrary *liboverride = object->id.override_library;
|
||||
IDOverrideLibraryProperty *op;
|
||||
|
||||
op = BKE_lib_override_library_property_find(liboverride, "modifiers");
|
||||
if (op != NULL) {
|
||||
LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
|
||||
if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
|
||||
continue;
|
||||
}
|
||||
ModifierData *mod_anchor = BLI_listbase_string_or_index_find(&object->modifiers,
|
||||
opop->subitem_local_name,
|
||||
offsetof(ModifierData, name),
|
||||
opop->subitem_local_index);
|
||||
if (mod_anchor == NULL || mod_anchor->next == NULL) {
|
||||
/* Invalid case, just remove that override property operation. */
|
||||
CLOG_ERROR(&LOG, "Could not find anchor or source modifiers in stored override data");
|
||||
BKE_lib_override_library_property_operation_delete(op, opop);
|
||||
continue;
|
||||
}
|
||||
ModifierData *mod_src = mod_anchor->next;
|
||||
opop->subitem_reference_name = opop->subitem_local_name;
|
||||
opop->subitem_local_name = BLI_strdup(mod_src->name);
|
||||
opop->subitem_reference_index = opop->subitem_local_index;
|
||||
opop->subitem_local_index++;
|
||||
}
|
||||
}
|
||||
|
||||
op = BKE_lib_override_library_property_find(liboverride, "grease_pencil_modifiers");
|
||||
if (op != NULL) {
|
||||
LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
|
||||
if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
|
||||
continue;
|
||||
}
|
||||
GpencilModifierData *gp_mod_anchor = BLI_listbase_string_or_index_find(
|
||||
&object->greasepencil_modifiers,
|
||||
opop->subitem_local_name,
|
||||
offsetof(GpencilModifierData, name),
|
||||
opop->subitem_local_index);
|
||||
if (gp_mod_anchor == NULL || gp_mod_anchor->next == NULL) {
|
||||
/* Invalid case, just remove that override property operation. */
|
||||
CLOG_ERROR(&LOG, "Could not find anchor GP modifier in stored override data");
|
||||
BKE_lib_override_library_property_operation_delete(op, opop);
|
||||
continue;
|
||||
}
|
||||
GpencilModifierData *gp_mod_src = gp_mod_anchor->next;
|
||||
opop->subitem_reference_name = opop->subitem_local_name;
|
||||
opop->subitem_local_name = BLI_strdup(gp_mod_src->name);
|
||||
opop->subitem_reference_index = opop->subitem_local_index;
|
||||
opop->subitem_local_index++;
|
||||
}
|
||||
}
|
||||
|
||||
op = BKE_lib_override_library_property_find(liboverride, "constraints");
|
||||
if (op != NULL) {
|
||||
version_liboverride_rnacollections_insertion_object_constraints(&object->constraints, op);
|
||||
}
|
||||
|
||||
if (object->pose != NULL) {
|
||||
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
|
||||
char rna_path[FILE_MAXFILE];
|
||||
BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].constraints", pchan->name);
|
||||
op = BKE_lib_override_library_property_find(liboverride, rna_path);
|
||||
if (op != NULL) {
|
||||
version_liboverride_rnacollections_insertion_object_constraints(&pchan->constraints, op);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void version_liboverride_rnacollections_insertion_animdata(ID *id)
|
||||
{
|
||||
AnimData *anim_data = BKE_animdata_from_id(id);
|
||||
if (anim_data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
IDOverrideLibrary *liboverride = id->override_library;
|
||||
IDOverrideLibraryProperty *op;
|
||||
|
||||
op = BKE_lib_override_library_property_find(liboverride, "animation_data.nla_tracks");
|
||||
if (op != NULL) {
|
||||
LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
|
||||
if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
|
||||
continue;
|
||||
}
|
||||
/* NLA tracks are only referenced by index, which limits possibilities, basically they are
|
||||
* always added at the end of the list, see #rna_NLA_tracks_override_apply.
|
||||
*
|
||||
* This makes things simple here. */
|
||||
opop->subitem_reference_name = opop->subitem_local_name;
|
||||
opop->subitem_local_name = NULL;
|
||||
opop->subitem_reference_index = opop->subitem_local_index;
|
||||
opop->subitem_local_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* NOLINTNEXTLINE: readability-function-size */
|
||||
void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
{
|
||||
|
@ -2170,18 +2310,9 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
* \note Be sure to check when bumping the version:
|
||||
* - "versioning_userdef.c", #blo_do_versions_userdef
|
||||
* - "versioning_userdef.c", #do_versions_theme
|
||||
*
|
||||
* \note Keep this message at the bottom of the function.
|
||||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 42)) {
|
||||
/* Use consistent socket identifiers for the math node.
|
||||
* The code to make unique identifiers from the names was inconsistent. */
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
if (ntree->type != NTREE_CUSTOM) {
|
||||
version_node_tree_socket_id_delim(ntree);
|
||||
|
@ -2235,4 +2366,35 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Special case to handle older in-dev 3.1 files, before change from 3.0 branch gets merged in
|
||||
* master. */
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 42) ||
|
||||
(bmain->versionfile == 301 && !MAIN_VERSION_ATLEAST(bmain, 301, 3))) {
|
||||
/* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers,
|
||||
* constraints and NLA tracks). */
|
||||
ID *id_iter;
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
|
||||
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) {
|
||||
version_liboverride_rnacollections_insertion_animdata(id_iter);
|
||||
if (GS(id_iter->name) == ID_OB) {
|
||||
version_liboverride_rnacollections_insertion_object((Object *)id_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_MAIN_ID_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
* \note Be sure to check when bumping the version:
|
||||
* - "versioning_userdef.c", #blo_do_versions_userdef
|
||||
* - "versioning_userdef.c", #do_versions_theme
|
||||
*
|
||||
* \note Keep this message at the bottom of the function.
|
||||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -211,11 +211,15 @@ typedef struct IDOverrideLibraryPropertyOperation {
|
|||
char _pad0[2];
|
||||
|
||||
/* Sub-item references, if needed (for arrays or collections only).
|
||||
* We need both reference and local values to allow e.g. insertion into collections
|
||||
* We need both reference and local values to allow e.g. insertion into RNA collections
|
||||
* (constraints, modifiers...).
|
||||
* In collection case, if names are defined, they are used in priority.
|
||||
* Names are pointers (instead of char[64]) to save some space, NULL when unset.
|
||||
* Indices are -1 when unset. */
|
||||
* In RNA collection case, if names are defined, they are used in priority.
|
||||
* Names are pointers (instead of char[64]) to save some space, NULL or empty string when unset.
|
||||
* Indices are -1 when unset.
|
||||
*
|
||||
* NOTE: For insertion operations in RNA collections, reference may not actually exist in the
|
||||
* linked reference data. It is used to identify the anchor of the insertion operation (i.e. the
|
||||
* item after or before which the new local item should be inserted), in the local override. */
|
||||
char *subitem_reference_name;
|
||||
char *subitem_local_name;
|
||||
int subitem_reference_index;
|
||||
|
|
|
@ -761,8 +761,8 @@ bool rna_NLA_tracks_override_apply(Main *bmain,
|
|||
/* This is not working so well with index-based insertion, especially in case some tracks get
|
||||
* added to lib linked data. So we simply add locale tracks at the end of the list always, order
|
||||
* of override operations should ensure order of local tracks is preserved properly. */
|
||||
if (opop->subitem_local_index >= 0) {
|
||||
nla_track_anchor = BLI_findlink(&anim_data_dst->nla_tracks, opop->subitem_local_index);
|
||||
if (opop->subitem_reference_index >= 0) {
|
||||
nla_track_anchor = BLI_findlink(&anim_data_dst->nla_tracks, opop->subitem_reference_index);
|
||||
}
|
||||
/* Otherwise we just insert in first position. */
|
||||
# else
|
||||
|
@ -773,9 +773,11 @@ bool rna_NLA_tracks_override_apply(Main *bmain,
|
|||
if (opop->subitem_local_index >= 0) {
|
||||
nla_track_src = BLI_findlink(&anim_data_src->nla_tracks, opop->subitem_local_index);
|
||||
}
|
||||
nla_track_src = nla_track_src ? nla_track_src->next : anim_data_src->nla_tracks.first;
|
||||
|
||||
BLI_assert(nla_track_src != NULL);
|
||||
if (nla_track_src == NULL) {
|
||||
BLI_assert(nla_track_src != NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
NlaTrack *nla_track_dst = BKE_nlatrack_copy(bmain, nla_track_src, true, 0);
|
||||
|
||||
|
|
|
@ -1705,27 +1705,20 @@ bool rna_Object_constraints_override_apply(Main *UNUSED(bmain),
|
|||
/* Remember that insertion operations are defined and stored in correct order, which means that
|
||||
* even if we insert several items in a row, we always insert first one, then second one, etc.
|
||||
* So we should always find 'anchor' constraint in both _src *and* _dst. */
|
||||
bConstraint *con_anchor = NULL;
|
||||
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
|
||||
con_anchor = BLI_findstring(
|
||||
&ob_dst->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
|
||||
}
|
||||
if (con_anchor == NULL && opop->subitem_local_index >= 0) {
|
||||
con_anchor = BLI_findlink(&ob_dst->constraints, opop->subitem_local_index);
|
||||
}
|
||||
/* Otherwise we just insert in first position. */
|
||||
const size_t name_offset = offsetof(bConstraint, name);
|
||||
bConstraint *con_anchor = BLI_listbase_string_or_index_find(&ob_dst->constraints,
|
||||
opop->subitem_reference_name,
|
||||
name_offset,
|
||||
opop->subitem_reference_index);
|
||||
/* If `con_anchor` is NULL, `con_src` will be inserted in first position. */
|
||||
|
||||
bConstraint *con_src = NULL;
|
||||
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
|
||||
con_src = BLI_findstring(
|
||||
&ob_src->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
|
||||
}
|
||||
if (con_src == NULL && opop->subitem_local_index >= 0) {
|
||||
con_src = BLI_findlink(&ob_src->constraints, opop->subitem_local_index);
|
||||
}
|
||||
con_src = con_src ? con_src->next : ob_src->constraints.first;
|
||||
bConstraint *con_src = BLI_listbase_string_or_index_find(
|
||||
&ob_src->constraints, opop->subitem_local_name, name_offset, opop->subitem_local_index);
|
||||
|
||||
BLI_assert(con_src != NULL);
|
||||
if (con_src == NULL) {
|
||||
BLI_assert(con_src != NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
bConstraint *con_dst = BKE_constraint_duplicate_ex(con_src, 0, true);
|
||||
|
||||
|
@ -1827,25 +1820,15 @@ bool rna_Object_modifiers_override_apply(Main *bmain,
|
|||
/* Remember that insertion operations are defined and stored in correct order, which means that
|
||||
* even if we insert several items in a row, we always insert first one, then second one, etc.
|
||||
* So we should always find 'anchor' modifier in both _src *and* _dst. */
|
||||
ModifierData *mod_anchor = NULL;
|
||||
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
|
||||
mod_anchor = BLI_findstring(
|
||||
&ob_dst->modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
|
||||
}
|
||||
if (mod_anchor == NULL && opop->subitem_local_index >= 0) {
|
||||
mod_anchor = BLI_findlink(&ob_dst->modifiers, opop->subitem_local_index);
|
||||
}
|
||||
/* Otherwise we just insert in first position. */
|
||||
const size_t name_offset = offsetof(ModifierData, name);
|
||||
ModifierData *mod_anchor = BLI_listbase_string_or_index_find(&ob_dst->modifiers,
|
||||
opop->subitem_reference_name,
|
||||
name_offset,
|
||||
opop->subitem_reference_index);
|
||||
/* If `mod_anchor` is NULL, `mod_src` will be inserted in first position. */
|
||||
|
||||
ModifierData *mod_src = NULL;
|
||||
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
|
||||
mod_src = BLI_findstring(
|
||||
&ob_src->modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
|
||||
}
|
||||
if (mod_src == NULL && opop->subitem_local_index >= 0) {
|
||||
mod_src = BLI_findlink(&ob_src->modifiers, opop->subitem_local_index);
|
||||
}
|
||||
mod_src = mod_src ? mod_src->next : ob_src->modifiers.first;
|
||||
ModifierData *mod_src = BLI_listbase_string_or_index_find(
|
||||
&ob_src->modifiers, opop->subitem_local_name, name_offset, opop->subitem_local_index);
|
||||
|
||||
if (mod_src == NULL) {
|
||||
BLI_assert(mod_src != NULL);
|
||||
|
@ -1934,25 +1917,18 @@ bool rna_Object_greasepencil_modifiers_override_apply(Main *bmain,
|
|||
/* Remember that insertion operations are defined and stored in correct order, which means that
|
||||
* even if we insert several items in a row, we always insert first one, then second one, etc.
|
||||
* So we should always find 'anchor' modifier in both _src *and* _dst. */
|
||||
GpencilModifierData *mod_anchor = NULL;
|
||||
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
|
||||
mod_anchor = BLI_findstring(
|
||||
&ob_dst->greasepencil_modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
|
||||
}
|
||||
if (mod_anchor == NULL && opop->subitem_local_index >= 0) {
|
||||
mod_anchor = BLI_findlink(&ob_dst->greasepencil_modifiers, opop->subitem_local_index);
|
||||
}
|
||||
/* Otherwise we just insert in first position. */
|
||||
const size_t name_offset = offsetof(GpencilModifierData, name);
|
||||
GpencilModifierData *mod_anchor = BLI_listbase_string_or_index_find(
|
||||
&ob_dst->greasepencil_modifiers,
|
||||
opop->subitem_reference_name,
|
||||
name_offset,
|
||||
opop->subitem_reference_index);
|
||||
/* If `mod_anchor` is NULL, `mod_src` will be inserted in first position. */
|
||||
|
||||
GpencilModifierData *mod_src = NULL;
|
||||
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
|
||||
mod_src = BLI_findstring(
|
||||
&ob_src->greasepencil_modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
|
||||
}
|
||||
if (mod_src == NULL && opop->subitem_local_index >= 0) {
|
||||
mod_src = BLI_findlink(&ob_src->greasepencil_modifiers, opop->subitem_local_index);
|
||||
}
|
||||
mod_src = mod_src ? mod_src->next : ob_src->greasepencil_modifiers.first;
|
||||
GpencilModifierData *mod_src = BLI_listbase_string_or_index_find(&ob_src->greasepencil_modifiers,
|
||||
opop->subitem_local_name,
|
||||
name_offset,
|
||||
opop->subitem_local_index);
|
||||
|
||||
if (mod_src == NULL) {
|
||||
BLI_assert(mod_src != NULL);
|
||||
|
|
|
@ -682,29 +682,18 @@ bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain),
|
|||
/* Remember that insertion operations are defined and stored in correct order, which means that
|
||||
* even if we insert several items in a row, we always insert first one, then second one, etc.
|
||||
* So we should always find 'anchor' constraint in both _src *and* _dst */
|
||||
bConstraint *con_anchor = NULL;
|
||||
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
|
||||
con_anchor = BLI_findstring(
|
||||
&pchan_dst->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
|
||||
}
|
||||
if (con_anchor == NULL && opop->subitem_local_index >= 0) {
|
||||
con_anchor = BLI_findlink(&pchan_dst->constraints, opop->subitem_local_index);
|
||||
}
|
||||
/* Otherwise we just insert in first position. */
|
||||
const size_t name_offset = offsetof(bConstraint, name);
|
||||
bConstraint *con_anchor = BLI_listbase_string_or_index_find(&pchan_dst->constraints,
|
||||
opop->subitem_reference_name,
|
||||
name_offset,
|
||||
opop->subitem_reference_index);
|
||||
/* If `con_anchor` is NULL, `con_src` will be inserted in first position. */
|
||||
|
||||
bConstraint *con_src = NULL;
|
||||
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
|
||||
con_src = BLI_findstring(
|
||||
&pchan_src->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
|
||||
}
|
||||
if (con_src == NULL && opop->subitem_local_index >= 0) {
|
||||
con_src = BLI_findlink(&pchan_src->constraints, opop->subitem_local_index);
|
||||
}
|
||||
con_src = con_src ? con_src->next : pchan_src->constraints.first;
|
||||
bConstraint *con_src = BLI_listbase_string_or_index_find(
|
||||
&pchan_src->constraints, opop->subitem_local_name, name_offset, opop->subitem_local_index);
|
||||
|
||||
if (con_src == NULL) {
|
||||
printf("%s: Could not find constraint to insert, doing nothing...\n", __func__);
|
||||
BLI_assert(0);
|
||||
BLI_assert(con_src != NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1916,16 +1916,21 @@ int rna_property_override_diff_default(Main *bmain,
|
|||
|
||||
/* Collections do not support replacement of their data (except for collections of ID
|
||||
* pointers), since they do not support removing, only in *some* cases, insertion. We
|
||||
* also assume then that _a data is the one where things are inserted. */
|
||||
* also assume then that _a data is the one where things are inserted.
|
||||
*
|
||||
* NOTE: In insertion case, both 'local' and 'reference' (aka anchor) sub-item
|
||||
* identifiers refer to collection items in the local override. The 'reference' may match
|
||||
* an item in the linked reference data, but it can also be another local-only item added
|
||||
* by a previous INSERT operation. */
|
||||
if (is_valid_for_insertion && use_collection_insertion) {
|
||||
op = BKE_lib_override_library_property_get(override, rna_path, &created);
|
||||
|
||||
BKE_lib_override_library_property_operation_get(op,
|
||||
IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
|
||||
NULL,
|
||||
no_prop_name ? NULL : prev_propname_a,
|
||||
-1,
|
||||
no_prop_name ? NULL : propname_a,
|
||||
idx_a - 1,
|
||||
idx_a,
|
||||
true,
|
||||
NULL,
|
||||
NULL);
|
||||
|
|
Loading…
Reference in New Issue