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 ----------- 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 f8895dca065..9514f1362d7 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 ccd69f2639f..5444a2eb058 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 240d7bb86af..d7a56c078fd 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)) { @@ -1840,6 +1849,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 47a55163c03..64d5c89fb60 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 bf3a32fa94b..be3f61b7c89 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) {