From 6e70b755ceecf9ae9a7e139e947da705774c3521 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 6 Jun 2025 10:58:23 +0200 Subject: [PATCH 1/2] Fix: PyAPI Docs: Document more msgbus limitations Added the following notes to documentation: - `msgbus` interaction with undo system that particularly makes it not completely reliable, since users they easily skip it's effect. - Details on when and how often message bus updates are triggered. Pull Request: https://projects.blender.org/blender/blender/pulls/138557 --- doc/python_api/examples/bpy.msgbus.1.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/python_api/examples/bpy.msgbus.1.py b/doc/python_api/examples/bpy.msgbus.1.py index 8164272d521..c33d5788ddf 100644 --- a/doc/python_api/examples/bpy.msgbus.1.py +++ b/doc/python_api/examples/bpy.msgbus.1.py @@ -17,6 +17,13 @@ The following updates do **not** trigger message bus notifications: - Moving objects in the 3D Viewport. - Changes performed by the animation system. +Changes done from ``msgbus`` callbacks are not included in related undo steps, +so users can easily skip their effects by using Undo followed by Redo. + +Unlike properties ``update`` callbacks, message bus update callbacks are postponed +until all operators have finished executing. +Additionally, for each property the callback is only triggered once per update cycle, +even if the property was changed multiple times during that period. Example Use ----------- From f6a9f082e9353848c5c6dbf6b3e1d86edcc28b43 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 6 Jun 2025 11:49:54 +0200 Subject: [PATCH 2/2] Core: Add data-level support for new 'system IDprops' storage for Blender 4.5 forward compatibility with 5.0 blendfiles This mainly adds DNA level IDProp storage for system properties, their handling in data management code, and the forward-versioning code copying back content from system properties into 'all-in-one' single IDProperties storage, for data types that will support both in Blender 5.0. There is no user-facing changes expected here. Part of #123232. Pull Request: https://projects.blender.org/blender/blender/pulls/139257 --- .../animrig/intern/bone_collections.cc | 16 +++++- source/blender/blenkernel/BKE_armature.hh | 7 +++ source/blender/blenkernel/intern/action.cc | 21 ++++++- source/blender/blenkernel/intern/armature.cc | 37 ++++++++++++ .../intern/grease_pencil_convert_legacy.cc | 1 + source/blender/blenkernel/intern/layer.cc | 11 ++++ source/blender/blenkernel/intern/lib_id.cc | 7 +++ .../blenkernel/intern/lib_id_delete.cc | 5 ++ source/blender/blenkernel/intern/lib_query.cc | 8 +++ source/blender/blenkernel/intern/object.cc | 6 ++ source/blender/blenkernel/intern/paint.cc | 1 + .../blender/blenkernel/intern/pose_backup.cc | 13 ++++- source/blender/blenkernel/intern/scene.cc | 12 ++++ source/blender/blenloader/intern/readfile.cc | 11 ++++ .../blenloader/intern/versioning_450.cc | 57 +++++++++++++++++++ .../blenloader/intern/versioning_common.hh | 4 ++ .../blender/editors/armature/armature_add.cc | 4 ++ .../editors/armature/armature_intern.hh | 1 + .../editors/armature/armature_relations.cc | 3 + .../editors/armature/armature_utils.cc | 19 +++++++ .../editors/armature/pose_transform.cc | 12 ++++ source/blender/editors/armature/pose_utils.cc | 4 ++ .../BlenderStrokeRenderer.cpp | 4 ++ source/blender/makesdna/DNA_ID.h | 10 ++++ source/blender/makesdna/DNA_action_types.h | 10 ++++ source/blender/makesdna/DNA_armature_types.h | 15 +++++ source/blender/makesdna/DNA_layer_types.h | 7 +++ source/blender/makesdna/DNA_sequence_types.h | 8 ++- source/blender/sequencer/SEQ_iterator.hh | 4 ++ source/blender/sequencer/intern/iterator.cc | 22 +++++++ source/blender/sequencer/intern/sequencer.cc | 11 ++++ 31 files changed, 346 insertions(+), 5 deletions(-) diff --git a/source/blender/animrig/intern/bone_collections.cc b/source/blender/animrig/intern/bone_collections.cc index e965f0e224a..9f49dfca029 100644 --- a/source/blender/animrig/intern/bone_collections.cc +++ b/source/blender/animrig/intern/bone_collections.cc @@ -63,8 +63,6 @@ BoneCollection *ANIM_bonecoll_new(const char *name) STRNCPY_UTF8(bcoll->name, name); bcoll->flags = default_flags; - bcoll->prop = nullptr; - return bcoll; } @@ -76,6 +74,9 @@ void ANIM_bonecoll_free(BoneCollection *bcoll, const bool do_id_user_count) if (bcoll->prop) { IDP_FreeProperty_ex(bcoll->prop, do_id_user_count); } + if (bcoll->system_properties) { + IDP_FreeProperty_ex(bcoll->system_properties, do_id_user_count); + } MEM_delete(bcoll); } @@ -258,6 +259,10 @@ static BoneCollection *copy_and_update_ownership(const bArmature *armature_dst, bcoll->prop = IDP_CopyProperty_ex(bcoll_to_copy->prop, 0 /*do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT*/); } + if (bcoll->system_properties) { + bcoll->system_properties = IDP_CopyProperty_ex( + bcoll_to_copy->system_properties, 0 /*do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT*/); + } /* Remap the bone pointers to the given armature, as `bcoll_to_copy` is * assumed to be owned by another armature. */ @@ -1406,6 +1411,10 @@ blender::Map ANIM_bonecoll_array_copy_no_mem bcoll_dst->prop = IDP_CopyProperty_ex(bcoll_src->prop, do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT); } + if (bcoll_src->system_properties) { + bcoll_dst->system_properties = IDP_CopyProperty_ex( + bcoll_src->system_properties, do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT); + } (*bcoll_array_dst)[i] = bcoll_dst; @@ -1425,6 +1434,9 @@ void ANIM_bonecoll_array_free(BoneCollection ***bcoll_array, if (bcoll->prop) { IDP_FreeProperty_ex(bcoll->prop, do_id_user); } + if (bcoll->system_properties) { + IDP_FreeProperty_ex(bcoll->system_properties, do_id_user); + } /* This will usually already be empty, because the passed BoneCollection * list is usually from ANIM_bonecoll_listbase_copy_no_membership(). diff --git a/source/blender/blenkernel/BKE_armature.hh b/source/blender/blenkernel/BKE_armature.hh index ad4fde98ed9..3da78d9a3d2 100644 --- a/source/blender/blenkernel/BKE_armature.hh +++ b/source/blender/blenkernel/BKE_armature.hh @@ -38,6 +38,13 @@ struct EditBone { EditBone *next, *prev; /** User-Defined Properties on this Bone */ IDProperty *prop; + /** + * System-Defined Properties storage. + * + * In Blender 4.5, only used to ensure forward compatibility with 5.x blendfiles, and data + * management consistency. + */ + IDProperty *system_properties; /** * Edit-bones have a one-way link (i.e. children refer * to parents. This is converted to a two-way link for diff --git a/source/blender/blenkernel/intern/action.cc b/source/blender/blenkernel/intern/action.cc index a693e9197e3..8e362743d31 100644 --- a/source/blender/blenkernel/intern/action.cc +++ b/source/blender/blenkernel/intern/action.cc @@ -1340,6 +1340,9 @@ void BKE_pose_copy_data_ex(bPose **dst, if (pchan->prop) { pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag); } + if (pchan->system_properties) { + pchan->system_properties = IDP_CopyProperty_ex(pchan->system_properties, flag); + } pchan->draw_data = nullptr; /* Drawing cache, no need to copy. */ @@ -1537,6 +1540,10 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user) IDP_FreeProperty_ex(pchan->prop, do_id_user); pchan->prop = nullptr; } + if (pchan->system_properties) { + IDP_FreeProperty_ex(pchan->system_properties, do_id_user); + pchan->system_properties = nullptr; + } /* Cached data, for new draw manager rendering code. */ MEM_SAFE_FREE(pchan->draw_data); @@ -1664,13 +1671,21 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f /* id-properties */ if (pchan->prop) { - /* unlikely but possible it exists */ + /* Unlikely, but possible that it exists. */ IDP_FreeProperty(pchan->prop); pchan->prop = nullptr; } if (pchan_from->prop) { pchan->prop = IDP_CopyProperty(pchan_from->prop); } + if (pchan->system_properties) { + /* Unlikely, but possible that it exists. */ + IDP_FreeProperty(pchan->system_properties); + pchan->system_properties = nullptr; + } + if (pchan_from->system_properties) { + pchan->system_properties = IDP_CopyProperty(pchan_from->system_properties); + } /* custom shape */ pchan->custom = pchan_from->custom; @@ -2074,6 +2089,8 @@ void BKE_pose_blend_write(BlendWriter *writer, bPose *pose, bArmature *arm) if (chan->prop) { IDP_BlendWrite(writer, chan->prop); } + /* Never write system_properties in Blender 4.5, will be reset to `nullptr` by reading code (by + * the matching call to #BLO_read_struct). */ BKE_constraint_blend_write(writer, &chan->constraints); @@ -2138,6 +2155,8 @@ void BKE_pose_blend_read_data(BlendDataReader *reader, ID *id_owner, bPose *pose BLO_read_struct(reader, IDProperty, &pchan->prop); IDP_BlendDataRead(reader, &pchan->prop); + BLO_read_struct(reader, IDProperty, &pchan->system_properties); + IDP_BlendDataRead(reader, &pchan->system_properties); BLO_read_struct(reader, bMotionPath, &pchan->mpath); if (pchan->mpath) { diff --git a/source/blender/blenkernel/intern/armature.cc b/source/blender/blenkernel/intern/armature.cc index 5479e287ae7..41a9dbd0ba8 100644 --- a/source/blender/blenkernel/intern/armature.cc +++ b/source/blender/blenkernel/intern/armature.cc @@ -109,6 +109,9 @@ static void copy_bone_collection(bArmature *armature_dst, if (bcoll_dst->prop) { bcoll_dst->prop = IDP_CopyProperty_ex(bcoll_dst->prop, lib_id_flag); } + if (bcoll_dst->system_properties) { + bcoll_dst->system_properties = IDP_CopyProperty_ex(bcoll_dst->system_properties, lib_id_flag); + } /* Bone references. */ BLI_duplicatelist(&bcoll_dst->bones, &bcoll_dst->bones); @@ -226,6 +229,11 @@ static void armature_foreach_id_bone(Bone *bone, LibraryForeachIDData *data) data, IDP_foreach_property(bone->prop, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); })); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(bone->system_properties, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { + BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); + })); LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) { BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(curbone, data)); @@ -238,6 +246,12 @@ static void armature_foreach_id_editbone(EditBone *edit_bone, LibraryForeachIDDa data, IDP_foreach_property(edit_bone->prop, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); })); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property( + edit_bone->system_properties, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { + BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); + })); } static void armature_foreach_id_bone_collection(BoneCollection *bcoll, LibraryForeachIDData *data) @@ -246,6 +260,11 @@ static void armature_foreach_id_bone_collection(BoneCollection *bcoll, LibraryFo data, IDP_foreach_property(bcoll->prop, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); })); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(bcoll->system_properties, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { + BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); + })); } static void armature_foreach_id(ID *id, LibraryForeachIDData *data) @@ -283,6 +302,8 @@ static void write_bone(BlendWriter *writer, Bone *bone) if (bone->prop) { IDP_BlendWrite(writer, bone->prop); } + /* Never write system_properties in Blender 4.5, will be reset to `nullptr` by reading code (by + * the matching call to #BLO_read_struct). */ /* Write Children */ LISTBASE_FOREACH (Bone *, cbone, &bone->childbase) { @@ -300,6 +321,8 @@ static void write_bone_collection(BlendWriter *writer, BoneCollection *bcoll) if (bcoll->prop) { IDP_BlendWrite(writer, bcoll->prop); } + /* Never write system_properties in Blender 4.5, will be reset to `nullptr` by reading code (by + * the matching call to #BLO_read_struct). */ BLO_write_struct_list(writer, BoneCollectionMember, &bcoll->bones); } @@ -356,8 +379,11 @@ static void armature_blend_write(BlendWriter *writer, ID *id, const void *id_add static void direct_link_bones(BlendDataReader *reader, Bone *bone) { BLO_read_struct(reader, Bone, &bone->parent); + BLO_read_struct(reader, IDProperty, &bone->prop); IDP_BlendDataRead(reader, &bone->prop); + BLO_read_struct(reader, IDProperty, &bone->system_properties); + IDP_BlendDataRead(reader, &bone->system_properties); BLO_read_struct(reader, Bone, &bone->bbone_next); BLO_read_struct(reader, Bone, &bone->bbone_prev); @@ -377,6 +403,8 @@ static void direct_link_bone_collection(BlendDataReader *reader, BoneCollection { BLO_read_struct(reader, IDProperty, &bcoll->prop); IDP_BlendDataRead(reader, &bcoll->prop); + BLO_read_struct(reader, IDProperty, &bcoll->system_properties); + IDP_BlendDataRead(reader, &bcoll->system_properties); BLO_read_struct_list(reader, BoneCollectionMember, &bcoll->bones); LISTBASE_FOREACH (BoneCollectionMember *, member, &bcoll->bones) { @@ -538,6 +566,9 @@ void BKE_armature_bonelist_free(ListBase *lb, const bool do_id_user) if (bone->prop) { IDP_FreeProperty_ex(bone->prop, do_id_user); } + if (bone->system_properties) { + IDP_FreeProperty_ex(bone->system_properties, do_id_user); + } BLI_freelistN(&bone->runtime.collections); BKE_armature_bonelist_free(&bone->childbase, do_id_user); } @@ -551,6 +582,9 @@ void BKE_armature_editbonelist_free(ListBase *lb, const bool do_id_user) if (edit_bone->prop) { IDP_FreeProperty_ex(edit_bone->prop, do_id_user); } + if (edit_bone->system_properties) { + IDP_FreeProperty_ex(edit_bone->system_properties, do_id_user); + } BLI_remlink_safe(lb, edit_bone); MEM_freeN(edit_bone); } @@ -571,6 +605,9 @@ static void copy_bonechildren(Bone *bone_dst, if (bone_src->prop) { bone_dst->prop = IDP_CopyProperty_ex(bone_src->prop, flag); } + if (bone_src->system_properties) { + bone_dst->system_properties = IDP_CopyProperty_ex(bone_src->system_properties, flag); + } /* Clear the runtime cache of the collection relations, these will be * reconstructed after the entire armature duplication is done. Don't free, diff --git a/source/blender/blenkernel/intern/grease_pencil_convert_legacy.cc b/source/blender/blenkernel/intern/grease_pencil_convert_legacy.cc index 9945c712ea8..919c7173fab 100644 --- a/source/blender/blenkernel/intern/grease_pencil_convert_legacy.cc +++ b/source/blender/blenkernel/intern/grease_pencil_convert_legacy.cc @@ -1036,6 +1036,7 @@ static void legacy_gpencil_to_grease_pencil(ConversionData &conversion_data, BLI_assert(!grease_pencil.id.properties); if (gpd.id.properties) { grease_pencil.id.properties = IDP_CopyProperty(gpd.id.properties); + grease_pencil.id.system_properties = IDP_CopyProperty(gpd.id.properties); } /** Convert Grease Pencil data flag. */ diff --git a/source/blender/blenkernel/intern/layer.cc b/source/blender/blenkernel/intern/layer.cc index 498b0628a2c..396e9899103 100644 --- a/source/blender/blenkernel/intern/layer.cc +++ b/source/blender/blenkernel/intern/layer.cc @@ -270,6 +270,9 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user) if (view_layer->id_properties) { IDP_FreeProperty_ex(view_layer->id_properties, do_id_user); } + if (view_layer->system_properties) { + IDP_FreeProperty_ex(view_layer->system_properties, do_id_user); + } MEM_SAFE_FREE(view_layer->object_bases_array); @@ -503,6 +506,10 @@ void BKE_view_layer_copy_data(Scene *scene_dst, if (view_layer_dst->id_properties != nullptr) { view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag); } + if (view_layer_dst->system_properties != nullptr) { + view_layer_dst->system_properties = IDP_CopyProperty_ex(view_layer_dst->system_properties, + flag); + } BKE_freestyle_config_copy( &view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag); @@ -2395,6 +2402,8 @@ void BKE_view_layer_blend_write(BlendWriter *writer, const Scene *scene, ViewLay if (view_layer->id_properties) { IDP_BlendWrite(writer, view_layer->id_properties); } + /* Never write system_properties in Blender 4.5, will be reset to `nullptr` by reading code (by + * the matching call to #BLO_read_struct). */ LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) { BLO_write_struct(writer, FreestyleModuleConfig, fmc); @@ -2454,6 +2463,8 @@ void BKE_view_layer_blend_read_data(BlendDataReader *reader, ViewLayer *view_lay BLO_read_struct(reader, IDProperty, &view_layer->id_properties); IDP_BlendDataRead(reader, &view_layer->id_properties); + BLO_read_struct(reader, IDProperty, &view_layer->system_properties); + IDP_BlendDataRead(reader, &view_layer->system_properties); BLO_read_struct_list(reader, FreestyleModuleConfig, &(view_layer->freestyle_config.modules)); BLO_read_struct_list(reader, FreestyleLineSet, &(view_layer->freestyle_config.linesets)); diff --git a/source/blender/blenkernel/intern/lib_id.cc b/source/blender/blenkernel/intern/lib_id.cc index 3e9af31dc14..772d3379cbc 100644 --- a/source/blender/blenkernel/intern/lib_id.cc +++ b/source/blender/blenkernel/intern/lib_id.cc @@ -943,6 +943,8 @@ static void id_swap(Main *bmain, /* Exception: IDProperties. */ id_a->properties = id_b_back.properties; id_b->properties = id_a_back.properties; + id_a->system_properties = id_b_back.system_properties; + id_b->system_properties = id_a_back.system_properties; /* Exception: recalc flags. */ id_a->recalc = id_b_back.recalc; id_b->recalc = id_a_back.recalc; @@ -1609,6 +1611,9 @@ void BKE_libblock_copy_in_lib(Main *bmain, if (id->properties) { new_id->properties = IDP_CopyProperty_ex(id->properties, copy_data_flag); } + if (id->system_properties) { + new_id->system_properties = IDP_CopyProperty_ex(id->system_properties, copy_data_flag); + } /* This is never duplicated, only one existing ID should have a given weak ref to library/ID. */ new_id->library_weak_reference = nullptr; @@ -2617,6 +2622,8 @@ void BKE_id_blend_write(BlendWriter *writer, ID *id) if (id->properties && !ELEM(GS(id->name), ID_WM)) { IDP_BlendWrite(writer, id->properties); } + /* Never write system_properties in Blender 4.5, will be reset to `nullptr` by reading code (by + * the matching call to #BLO_read_struct). */ BKE_animdata_blend_write(writer, id); diff --git a/source/blender/blenkernel/intern/lib_id_delete.cc b/source/blender/blenkernel/intern/lib_id_delete.cc index 6e33aeb08d6..1f465e2d56f 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.cc +++ b/source/blender/blenkernel/intern/lib_id_delete.cc @@ -52,6 +52,11 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user) MEM_freeN(id->properties); id->properties = nullptr; } + if (id->system_properties) { + IDP_FreePropertyContent_ex(id->system_properties, do_id_user); + MEM_freeN(id->system_properties); + id->system_properties = nullptr; + } if (id->override_library) { BKE_lib_override_library_free(&id->override_library, do_id_user); diff --git a/source/blender/blenkernel/intern/lib_query.cc b/source/blender/blenkernel/intern/lib_query.cc index aa09f502d02..4dba33d9681 100644 --- a/source/blender/blenkernel/intern/lib_query.cc +++ b/source/blender/blenkernel/intern/lib_query.cc @@ -393,6 +393,14 @@ static bool library_foreach_ID_link(Main *bmain, return false; } + IDP_foreach_property(id->system_properties, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { + BKE_lib_query_idpropertiesForeachIDLink_callback(prop, &data); + }); + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; + } + AnimData *adt = BKE_animdata_from_id(id); if (adt) { BKE_animdata_foreach_id(adt, &data); diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 939ebc55a04..90b44f7855b 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -428,6 +428,12 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) data, IDP_foreach_property(pchan->prop, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); })); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property( + pchan->system_properties, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { + BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); + })); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, pchan->custom, IDWALK_CB_USER); BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 2c9128bb961..575aa3c868d 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -135,6 +135,7 @@ static void palette_undo_preserve(BlendLibReader * /*reader*/, ID *id_new, ID *i * fairly delicate. */ BKE_lib_id_swap(nullptr, id_new, id_old, false, 0); std::swap(id_new->properties, id_old->properties); + std::swap(id_new->system_properties, id_old->system_properties); } IDTypeInfo IDType_ID_PAL = { diff --git a/source/blender/blenkernel/intern/pose_backup.cc b/source/blender/blenkernel/intern/pose_backup.cc index 53fa1575113..cd51935adcd 100644 --- a/source/blender/blenkernel/intern/pose_backup.cc +++ b/source/blender/blenkernel/intern/pose_backup.cc @@ -36,7 +36,9 @@ struct PoseChannelBackup { bPoseChannel olddata; /* Backup of pose channel. */ IDProperty *oldprops; /* Backup copy (needs freeing) of pose channel's ID properties. */ - const Object *owner; /* The object to which this pose channel belongs. */ + /* Backup copy (needs freeing) of pose channel's system IDProperties. */ + IDProperty *old_system_properties; + const Object *owner; /* The object to which this pose channel belongs. */ }; struct PoseBackup { @@ -84,6 +86,9 @@ static void pose_backup_create(const Object *ob, if (pchan->prop) { chan_bak->oldprops = IDP_CopyProperty(pchan->prop); } + if (pchan->system_properties) { + chan_bak->old_system_properties = IDP_CopyProperty(pchan->system_properties); + } BLI_addtail(&pose_backup.backups, chan_bak); backed_up_bone_names.add_new(bone_name); @@ -163,6 +168,9 @@ void BKE_pose_backup_restore(const PoseBackup *pbd) if (chan_bak->oldprops) { IDP_SyncGroupValues(chan_bak->pchan->prop, chan_bak->oldprops); } + if (chan_bak->old_system_properties) { + IDP_SyncGroupValues(chan_bak->pchan->system_properties, chan_bak->old_system_properties); + } /* TODO: constraints settings aren't restored yet, * even though these could change (though not that likely) */ @@ -179,6 +187,9 @@ void BKE_pose_backup_free(PoseBackup *pbd) if (chan_bak->oldprops) { IDP_FreeProperty(chan_bak->oldprops); } + if (chan_bak->old_system_properties) { + IDP_FreeProperty(chan_bak->old_system_properties); + } BLI_freelinkN(&pbd->backups, chan_bak); } MEM_freeN(pbd); diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index 36e1e430ce2..e69f83067cd 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -815,6 +815,9 @@ static bool strip_foreach_member_id_cb(Strip *strip, void *user_data) IDP_foreach_property(strip->prop, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); }); + IDP_foreach_property(strip->system_properties, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { + BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); + }); LISTBASE_FOREACH (StripModifierData *, smd, &strip->modifiers) { FOREACHID_PROCESS_IDSUPER(data, smd->mask_id, IDWALK_CB_USER); } @@ -873,6 +876,12 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) IDP_foreach_property(view_layer->id_properties, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); })); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property( + view_layer->system_properties, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) { + BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data); + })); BKE_view_layer_synced_ensure(scene, view_layer); LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) { @@ -1834,6 +1843,9 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) if (sce->id.properties) { sce_copy->id.properties = IDP_CopyProperty(sce->id.properties); } + if (sce->id.system_properties) { + sce_copy->id.system_properties = IDP_CopyProperty(sce->id.system_properties); + } BKE_sound_destroy_scene(sce_copy); diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 14ac57d21d5..6cc826113d0 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -2118,6 +2118,11 @@ static void direct_link_id_common(BlendDataReader *reader, IDP_BlendDataRead(reader, &id->properties); } + if (id->system_properties) { + BLO_read_struct(reader, IDProperty, &id->system_properties); + IDP_BlendDataRead(reader, &id->system_properties); + } + id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK; /* NOTE: It is important to not clear the recalc flags for undo/redo. @@ -3089,6 +3094,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* Don't allow versioning to create new data-blocks. */ main->is_locked_for_linking = true; + /* Code ensuring conversion from new 'system IDProperties' in 5.0. This needs to run before any + * other data versioning. Otherwise, things like Cycles versioning code cannot work as expected. + * + * Merge (with overwrite) future system properties storage into current IDProperties. */ + version_forward_compat_system_idprops(main); + if (G.debug & G_DEBUG) { char build_commit_datetime[32]; time_t temp_time = main->build_commit_timestamp; diff --git a/source/blender/blenloader/intern/versioning_450.cc b/source/blender/blenloader/intern/versioning_450.cc index 017adca9d86..f6dfb955e93 100644 --- a/source/blender/blenloader/intern/versioning_450.cc +++ b/source/blender/blenloader/intern/versioning_450.cc @@ -33,6 +33,9 @@ #include "BKE_customdata.hh" #include "BKE_fcurve.hh" #include "BKE_grease_pencil.hh" +#include "BKE_idprop.hh" +#include "BKE_lib_id.hh" +#include "BKE_lib_query.hh" #include "BKE_main.hh" #include "BKE_mesh_legacy_convert.hh" #include "BKE_node.hh" @@ -55,6 +58,60 @@ // static CLG_LogRef LOG = {"blo.readfile.doversion"}; +void version_forward_compat_system_idprops(Main *bmain) +{ + auto idprops_process = [](IDProperty **idprops, IDProperty *system_idprops) -> void { + if (system_idprops) { + /* Other ID pointers have not yet been relinked, do not try to access them for refcounting. + */ + if (*idprops) { + IDP_MergeGroup_ex(*idprops, system_idprops, true, LIB_ID_CREATE_NO_USER_REFCOUNT); + } + else { + *idprops = IDP_CopyProperty_ex(system_idprops, LIB_ID_CREATE_NO_USER_REFCOUNT); + } + } + }; + + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + idprops_process(&id_iter->properties, id_iter->system_properties); + } + FOREACH_MAIN_ID_END; + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + idprops_process(&view_layer->id_properties, view_layer->system_properties); + } + + if (scene->ed != nullptr) { + blender::seq::for_each_callback(&scene->ed->seqbase, + [&idprops_process](Strip *strip) -> bool { + idprops_process(&strip->prop, strip->system_properties); + return true; + }); + } + } + + LISTBASE_FOREACH (Object *, object, &bmain->objects) { + if (!object->pose) { + continue; + } + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + idprops_process(&pchan->prop, pchan->system_properties); + } + } + + LISTBASE_FOREACH (bArmature *, armature, &bmain->armatures) { + for (BoneCollection *bcoll : armature->collections_span()) { + idprops_process(&bcoll->prop, bcoll->system_properties); + } + LISTBASE_FOREACH (Bone *, bone, &armature->bonebase) { + idprops_process(&bone->prop, bone->system_properties); + } + } +} + static void version_fix_fcurve_noise_offset(FCurve &fcurve) { LISTBASE_FOREACH (FModifier *, fcurve_modifier, &fcurve.modifiers) { diff --git a/source/blender/blenloader/intern/versioning_common.hh b/source/blender/blenloader/intern/versioning_common.hh index e14dbff0565..2657880abb8 100644 --- a/source/blender/blenloader/intern/versioning_common.hh +++ b/source/blender/blenloader/intern/versioning_common.hh @@ -194,6 +194,10 @@ void version_update_node_input( FunctionRef update_input_link); bNode *version_eevee_output_node_get(bNodeTree *ntree, int16_t node_type); + +/* Allow 4.5 to open 5.0+ files and recover their system-defined ID properties. */ +void version_forward_compat_system_idprops(Main *bmain); + bool all_scenes_use(Main *bmain, const blender::Span engines); /* Adjust the values of the given FCurve key frames by applying the given function. The function is diff --git a/source/blender/editors/armature/armature_add.cc b/source/blender/editors/armature/armature_add.cc index 02f9ef9202b..442b8e169a6 100644 --- a/source/blender/editors/armature/armature_add.cc +++ b/source/blender/editors/armature/armature_add.cc @@ -1048,6 +1048,9 @@ static void copy_pchan(EditBone *src_bone, EditBone *dst_bone, Object *src_ob, O if (src_bone->prop) { dst_bone->prop = IDP_CopyProperty(src_bone->prop); } + if (src_bone->system_properties) { + dst_bone->system_properties = IDP_CopyProperty(src_bone->system_properties); + } /* Lets duplicate the list of constraints that the * current bone has. @@ -1909,6 +1912,7 @@ static wmOperatorStatus armature_subdivide_exec(bContext *C, wmOperator *op) newbone->flag |= BONE_CONNECTED; newbone->prop = nullptr; + newbone->system_properties = nullptr; /* correct parent bones */ LISTBASE_FOREACH (EditBone *, tbone, arm->edbo) { diff --git a/source/blender/editors/armature/armature_intern.hh b/source/blender/editors/armature/armature_intern.hh index e052f917367..47f1a83cc37 100644 --- a/source/blender/editors/armature/armature_intern.hh +++ b/source/blender/editors/armature/armature_intern.hh @@ -164,6 +164,7 @@ struct tPChanFCurveLink { /** copy of custom properties at start of operator (to be restored before each modal step) */ IDProperty *oldprops; + IDProperty *old_system_properties; }; /* ----------- */ diff --git a/source/blender/editors/armature/armature_relations.cc b/source/blender/editors/armature/armature_relations.cc index 3c59ffa5654..69a27cb3937 100644 --- a/source/blender/editors/armature/armature_relations.cc +++ b/source/blender/editors/armature/armature_relations.cc @@ -291,6 +291,9 @@ static BoneCollection *join_armature_remap_collection( if (bcoll->prop) { new_bcoll->prop = IDP_CopyProperty_ex(bcoll->prop, 0); } + if (bcoll->system_properties) { + new_bcoll->system_properties = IDP_CopyProperty_ex(bcoll->system_properties, 0); + } bone_collection_by_name.add(bcoll->name, new_bcoll); return new_bcoll; diff --git a/source/blender/editors/armature/armature_utils.cc b/source/blender/editors/armature/armature_utils.cc index e6b3873312b..7d15a4e9efb 100644 --- a/source/blender/editors/armature/armature_utils.cc +++ b/source/blender/editors/armature/armature_utils.cc @@ -109,6 +109,9 @@ void bone_free(bArmature *arm, EditBone *bone) if (bone->prop) { IDP_FreeProperty(bone->prop); } + if (bone->system_properties) { + IDP_FreeProperty(bone->system_properties); + } /* Clear references from other edit bones. */ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) { @@ -523,6 +526,9 @@ static EditBone *make_boneList_recursive(ListBase *edbo, if (curBone->prop) { eBone->prop = IDP_CopyProperty(curBone->prop); } + if (curBone->system_properties) { + eBone->system_properties = IDP_CopyProperty(curBone->system_properties); + } BLI_addtail(edbo, eBone); @@ -744,6 +750,9 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm) if (eBone->prop) { newBone->prop = IDP_CopyProperty(eBone->prop); } + if (eBone->system_properties) { + newBone->system_properties = IDP_CopyProperty(eBone->system_properties); + } } /* Fix parenting in a separate pass to ensure ebone->bone connections are valid at this point. @@ -797,6 +806,9 @@ void ED_armature_edit_free(bArmature *arm) if (eBone->prop) { IDP_FreeProperty(eBone->prop); } + if (eBone->system_properties) { + IDP_FreeProperty(eBone->system_properties); + } BLI_freelistN(&eBone->bone_collections); } @@ -831,6 +843,9 @@ void ED_armature_ebone_listbase_free(ListBase *lb, const bool do_id_user) if (ebone->prop) { IDP_FreeProperty_ex(ebone->prop, do_id_user); } + if (ebone->system_properties) { + IDP_FreeProperty_ex(ebone->system_properties, do_id_user); + } BLI_freelistN(&ebone->bone_collections); @@ -850,6 +865,10 @@ void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src, const b ebone_dst->prop = IDP_CopyProperty_ex(ebone_dst->prop, do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT); } + if (ebone_dst->system_properties) { + ebone_dst->system_properties = IDP_CopyProperty_ex( + ebone_dst->system_properties, do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT); + } ebone_src->temp.ebone = ebone_dst; BLI_addtail(lb_dst, ebone_dst); } diff --git a/source/blender/editors/armature/pose_transform.cc b/source/blender/editors/armature/pose_transform.cc index a5338bc8f0f..4c011c1279e 100644 --- a/source/blender/editors/armature/pose_transform.cc +++ b/source/blender/editors/armature/pose_transform.cc @@ -767,6 +767,15 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, pchan->prop = IDP_CopyProperty(chan->prop); } } + if (chan->system_properties) { + /* Same logic as above for system IDProperties, for now. */ + if (pchan->system_properties) { + IDP_SyncGroupValues(pchan->system_properties, chan->system_properties); + } + else { + pchan->system_properties = IDP_CopyProperty(chan->system_properties); + } + } return pchan; } @@ -1397,6 +1406,9 @@ static wmOperatorStatus pose_clear_user_transforms_exec(bContext *C, wmOperator if (pchan->prop) { IDP_FreeProperty(pchan->prop); } + if (pchan->system_properties) { + IDP_FreeProperty(pchan->system_properties); + } } /* was copied without constraints */ diff --git a/source/blender/editors/armature/pose_utils.cc b/source/blender/editors/armature/pose_utils.cc index 1bfcfa8a67d..f95e0bac54b 100644 --- a/source/blender/editors/armature/pose_utils.cc +++ b/source/blender/editors/armature/pose_utils.cc @@ -226,6 +226,7 @@ static void fcurves_to_pchan_links_get(ListBase &pfLinks, Object &ob, bPoseChann /* Make copy of custom properties. */ if (pchan.prop && (transFlags & ACT_TRANS_PROP)) { pfl->oldprops = IDP_CopyProperty(pchan.prop); + pfl->old_system_properties = IDP_CopyProperty(pchan.system_properties); } } @@ -362,6 +363,9 @@ void poseAnim_mapping_reset(ListBase *pfLinks) if (pfl->oldprops) { IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops); } + if (pfl->old_system_properties) { + IDP_SyncGroupValues(pfl->pchan->system_properties, pfl->old_system_properties); + } } } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index c180d62de8b..485dd77f039 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -118,6 +118,10 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) if (old_scene->id.properties) { freestyle_scene->id.properties = IDP_CopyProperty_ex(old_scene->id.properties, 0); } + if (old_scene->id.system_properties) { + freestyle_scene->id.system_properties = IDP_CopyProperty_ex(old_scene->id.system_properties, + 0); + } // Copy eevee render settings. BKE_scene_copy_data_eevee(freestyle_scene, old_scene); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index afba5498f27..8fd37c284bf 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -442,6 +442,16 @@ typedef struct ID { IDProperty *properties; + /** + * System-defined custom properties storage. + * + * In Blender 4.5, only used to ensure forward compatibility with 5.x blendfiles, and data + * management consistency. + */ + IDProperty *system_properties; + + void *_pad1; + /** Reference linked ID which this one overrides. */ IDOverrideLibrary *override_library; diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index dd8ecb76551..e665f760a5b 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -287,6 +287,14 @@ typedef struct bPoseChannel { /** User-Defined Properties on this PoseChannel. */ IDProperty *prop; + /** + * System-defined custom properties storage. + * + * In Blender 4.5, only used to ensure forward compatibility with 5.x blendfiles, and data + * management consistency. + */ + IDProperty *system_properties; + /** Constraints that act on this PoseChannel. */ ListBase constraints; char name[/*MAXBONENAME*/ 64]; @@ -421,6 +429,8 @@ typedef struct bPoseChannel { BoneColor color; /* MUST be named the same as in Bone and EditBone structs. */ + void *_pad2; + /** Runtime data (keep last). */ struct bPoseChannel_Runtime runtime; } bPoseChannel; diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index b4e060e82f7..c00ab2d097b 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -61,6 +61,14 @@ typedef struct Bone { struct Bone *next, *prev; /** User-Defined Properties on this Bone. */ IDProperty *prop; + /** + * System-Defined Properties storage. + * + * In Blender 4.5, only used to ensure forward compatibility with 5.x blendfiles, and data + * management consistency. + */ + IDProperty *system_properties; + void *_pad0; /** Parent (IK parent if appropriate flag is set). */ struct Bone *parent; /** Children. */ @@ -276,6 +284,13 @@ typedef struct BoneCollection { /** Custom properties. */ struct IDProperty *prop; + /** + * Custom system IDProperties. + * + * In Blender 4.5, only used to ensure forward compatibility with 5.x blendfiles, and data + * management consistency. + */ + struct IDProperty *system_properties; #ifdef __cplusplus /** diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 474547fc7b2..ef2c3d87d84 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -178,6 +178,13 @@ typedef struct ViewLayer { struct World *world_override; /** Equivalent to datablocks ID properties. */ struct IDProperty *id_properties; + /** + * Equivalent to datablocks system-defined ID properties. + * + * In Blender 4.5, only used to ensure forward compatibility with 5.x blendfiles, and data + * management consistency. + */ + struct IDProperty *system_properties; struct FreestyleConfig freestyle_config; struct ViewLayerEEVEE eevee; diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 3c27617d3f1..aaaf599ed0f 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -296,6 +296,13 @@ typedef struct Strip { struct Stereo3dFormat *stereo3d_format; struct IDProperty *prop; + /** + * System-defined custom properties storage. + * + * In Blender 4.5, only used to ensure forward compatibility with 5.x blendfiles, and data + * management consistency. + */ + struct IDProperty *system_properties; /* modifiers */ ListBase modifiers; @@ -305,7 +312,6 @@ typedef struct Strip { float speed_factor; struct SeqRetimingKey *retiming_keys; - void *_pad5; int retiming_keys_num; char _pad6[4]; diff --git a/source/blender/sequencer/SEQ_iterator.hh b/source/blender/sequencer/SEQ_iterator.hh index 8c0421ca23b..38b11cdb3ea 100644 --- a/source/blender/sequencer/SEQ_iterator.hh +++ b/source/blender/sequencer/SEQ_iterator.hh @@ -8,6 +8,7 @@ * \ingroup sequencer */ +#include "BLI_function_ref.hh" #include "BLI_vector_set.hh" struct ListBase; @@ -32,6 +33,9 @@ using ForEachFunc = bool (*)(Strip *strip, void *user_data); */ void for_each_callback(ListBase *seqbase, ForEachFunc callback, void *user_data); +/** Same as above, but using a more modern FunctionRef as callback. */ +void for_each_callback(ListBase *seqbase, blender::FunctionRef callback); + /** * Expand set by running `strip_query_func()` for each strip, which will be used as reference. * Results of these queries will be merged into provided collection. diff --git a/source/blender/sequencer/intern/iterator.cc b/source/blender/sequencer/intern/iterator.cc index 6c1f16c16c5..cadbb17c759 100644 --- a/source/blender/sequencer/intern/iterator.cc +++ b/source/blender/sequencer/intern/iterator.cc @@ -39,11 +39,33 @@ static bool strip_for_each_recursive(ListBase *seqbase, ForEachFunc callback, vo return true; } +static bool strip_for_each_recursive(ListBase *seqbase, + blender::FunctionRef callback) +{ + LISTBASE_FOREACH (Strip *, strip, seqbase) { + if (!callback(strip)) { + /* Callback signaled stop, return. */ + return false; + } + if (strip->type == STRIP_TYPE_META) { + if (!strip_for_each_recursive(&strip->seqbase, callback)) { + return false; + } + } + } + return true; +} + void for_each_callback(ListBase *seqbase, ForEachFunc callback, void *user_data) { strip_for_each_recursive(seqbase, callback, user_data); } +void for_each_callback(ListBase *seqbase, blender::FunctionRef callback) +{ + strip_for_each_recursive(seqbase, callback); +} + VectorSet query_by_reference(Strip *strip_reference, const Scene *scene, ListBase *seqbase, diff --git a/source/blender/sequencer/intern/sequencer.cc b/source/blender/sequencer/intern/sequencer.cc index 50e27fcf87a..43e3512295d 100644 --- a/source/blender/sequencer/intern/sequencer.cc +++ b/source/blender/sequencer/intern/sequencer.cc @@ -214,6 +214,10 @@ static void seq_strip_free_ex(Scene *scene, IDP_FreePropertyContent_ex(strip->prop, do_id_user); MEM_freeN(strip->prop); } + if (strip->system_properties) { + IDP_FreePropertyContent_ex(strip->system_properties, do_id_user); + MEM_freeN(strip->system_properties); + } /* free modifiers */ modifier_clear(strip); @@ -534,6 +538,9 @@ static Strip *strip_duplicate(const Scene *scene_src, if (strip->prop) { strip_new->prop = IDP_CopyProperty_ex(strip->prop, flag); } + if (strip->system_properties) { + strip_new->system_properties = IDP_CopyProperty_ex(strip->system_properties, flag); + } if (strip_new->modifiers.first) { BLI_listbase_clear(&strip_new->modifiers); @@ -791,6 +798,8 @@ static bool strip_write_data_cb(Strip *strip, void *userdata) if (strip->prop) { IDP_BlendWrite(writer, strip->prop); } + /* Never write system_properties in Blender 4.5, will be reset to `nullptr` by reading code (by + * the matching call to #BLO_read_struct). */ modifier_blend_write(writer, &strip->modifiers); @@ -879,6 +888,8 @@ static bool strip_read_data_cb(Strip *strip, void *user_data) BLO_read_struct(reader, IDProperty, &strip->prop); IDP_BlendDataRead(reader, &strip->prop); + BLO_read_struct(reader, IDProperty, &strip->system_properties); + IDP_BlendDataRead(reader, &strip->system_properties); BLO_read_struct(reader, StripData, &strip->data); if (strip->data && strip->data->done == 0) {