Merge branch 'blender-v4.5-release'

This commit is contained in:
Bastien Montagne
2025-06-06 11:53:26 +02:00
32 changed files with 353 additions and 5 deletions

View File

@@ -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
-----------

View File

@@ -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<BoneCollection *, BoneCollection *> 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().

View File

@@ -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

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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. */

View File

@@ -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));

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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(

View File

@@ -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 = {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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) {

View File

@@ -194,6 +194,10 @@ void version_update_node_input(
FunctionRef<void(bNode *, bNodeSocket *, bNode *, bNodeSocket *)> 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<const char *> engines);
/* Adjust the values of the given FCurve key frames by applying the given function. The function is

View File

@@ -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) {

View File

@@ -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;
};
/* ----------- */

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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 */

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
/**

View File

@@ -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;

View File

@@ -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];

View File

@@ -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<bool(Strip *)> 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.

View File

@@ -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<bool(Strip *)> 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<bool(Strip *)> callback)
{
strip_for_each_recursive(seqbase, callback);
}
VectorSet<Strip *> query_by_reference(Strip *strip_reference,
const Scene *scene,
ListBase *seqbase,

View File

@@ -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) {