Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenloader/intern/versioning_300.cc')
-rw-r--r--source/blender/blenloader/intern/versioning_300.cc3668
1 files changed, 3668 insertions, 0 deletions
diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc
new file mode 100644
index 00000000000..a2bd7fd2fd1
--- /dev/null
+++ b/source/blender/blenloader/intern/versioning_300.cc
@@ -0,0 +1,3668 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup blenloader
+ */
+/* allow readfile to use deprecated functionality */
+#define DNA_DEPRECATED_ALLOW
+
+#include <cstring>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_curves_types.h"
+#include "DNA_genfile.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_lineart_types.h"
+#include "DNA_listBase.h"
+#include "DNA_mask_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_text_types.h"
+#include "DNA_workspace_types.h"
+
+#include "BKE_action.h"
+#include "BKE_anim_data.h"
+#include "BKE_animsys.h"
+#include "BKE_armature.h"
+#include "BKE_asset.h"
+#include "BKE_attribute.h"
+#include "BKE_collection.h"
+#include "BKE_colortools.h"
+#include "BKE_curve.h"
+#include "BKE_data_transfer.h"
+#include "BKE_deform.h"
+#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
+#include "BKE_idprop.h"
+#include "BKE_image.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_override.h"
+#include "BKE_main.h"
+#include "BKE_main_namemap.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_screen.h"
+
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+#include "RNA_prototypes.h"
+
+#include "BLO_readfile.h"
+
+#include "readfile.h"
+
+#include "SEQ_channels.h"
+#include "SEQ_iterator.h"
+#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
+
+#include "versioning_common.h"
+
+static CLG_LogRef LOG = {"blo.readfile.doversion"};
+
+static IDProperty *idproperty_find_ui_container(IDProperty *idprop_group)
+{
+ LISTBASE_FOREACH (IDProperty *, prop, &idprop_group->data.group) {
+ if (prop->type == IDP_GROUP && STREQ(prop->name, "_RNA_UI")) {
+ return prop;
+ }
+ }
+ return nullptr;
+}
+
+static void version_idproperty_move_data_int(IDPropertyUIDataInt *ui_data,
+ const IDProperty *prop_ui_data)
+{
+ IDProperty *min = IDP_GetPropertyFromGroup(prop_ui_data, "min");
+ if (min != nullptr) {
+ ui_data->min = ui_data->soft_min = IDP_coerce_to_int_or_zero(min);
+ }
+ IDProperty *max = IDP_GetPropertyFromGroup(prop_ui_data, "max");
+ if (max != nullptr) {
+ ui_data->max = ui_data->soft_max = IDP_coerce_to_int_or_zero(max);
+ }
+ IDProperty *soft_min = IDP_GetPropertyFromGroup(prop_ui_data, "soft_min");
+ if (soft_min != nullptr) {
+ ui_data->soft_min = IDP_coerce_to_int_or_zero(soft_min);
+ ui_data->soft_min = MIN2(ui_data->soft_min, ui_data->min);
+ }
+ IDProperty *soft_max = IDP_GetPropertyFromGroup(prop_ui_data, "soft_max");
+ if (soft_max != nullptr) {
+ ui_data->soft_max = IDP_coerce_to_int_or_zero(soft_max);
+ ui_data->soft_max = MAX2(ui_data->soft_max, ui_data->max);
+ }
+ IDProperty *step = IDP_GetPropertyFromGroup(prop_ui_data, "step");
+ if (step != nullptr) {
+ ui_data->step = IDP_coerce_to_int_or_zero(soft_max);
+ }
+ IDProperty *default_value = IDP_GetPropertyFromGroup(prop_ui_data, "default");
+ if (default_value != nullptr) {
+ if (default_value->type == IDP_ARRAY) {
+ if (default_value->subtype == IDP_INT) {
+ ui_data->default_array = static_cast<int *>(
+ MEM_malloc_arrayN(default_value->len, sizeof(int), __func__));
+ memcpy(ui_data->default_array, IDP_Array(default_value), sizeof(int) * default_value->len);
+ ui_data->default_array_len = default_value->len;
+ }
+ }
+ else if (default_value->type == IDP_INT) {
+ ui_data->default_value = IDP_coerce_to_int_or_zero(default_value);
+ }
+ }
+}
+
+static void version_idproperty_move_data_float(IDPropertyUIDataFloat *ui_data,
+ const IDProperty *prop_ui_data)
+{
+ IDProperty *min = IDP_GetPropertyFromGroup(prop_ui_data, "min");
+ if (min != nullptr) {
+ ui_data->min = ui_data->soft_min = IDP_coerce_to_double_or_zero(min);
+ }
+ IDProperty *max = IDP_GetPropertyFromGroup(prop_ui_data, "max");
+ if (max != nullptr) {
+ ui_data->max = ui_data->soft_max = IDP_coerce_to_double_or_zero(max);
+ }
+ IDProperty *soft_min = IDP_GetPropertyFromGroup(prop_ui_data, "soft_min");
+ if (soft_min != nullptr) {
+ ui_data->soft_min = IDP_coerce_to_double_or_zero(soft_min);
+ ui_data->soft_min = MAX2(ui_data->soft_min, ui_data->min);
+ }
+ IDProperty *soft_max = IDP_GetPropertyFromGroup(prop_ui_data, "soft_max");
+ if (soft_max != nullptr) {
+ ui_data->soft_max = IDP_coerce_to_double_or_zero(soft_max);
+ ui_data->soft_max = MIN2(ui_data->soft_max, ui_data->max);
+ }
+ IDProperty *step = IDP_GetPropertyFromGroup(prop_ui_data, "step");
+ if (step != nullptr) {
+ ui_data->step = IDP_coerce_to_float_or_zero(step);
+ }
+ IDProperty *precision = IDP_GetPropertyFromGroup(prop_ui_data, "precision");
+ if (precision != nullptr) {
+ ui_data->precision = IDP_coerce_to_int_or_zero(precision);
+ }
+ IDProperty *default_value = IDP_GetPropertyFromGroup(prop_ui_data, "default");
+ if (default_value != nullptr) {
+ if (default_value->type == IDP_ARRAY) {
+ const int array_len = default_value->len;
+ ui_data->default_array_len = array_len;
+ if (default_value->subtype == IDP_FLOAT) {
+ ui_data->default_array = static_cast<double *>(
+ MEM_malloc_arrayN(array_len, sizeof(double), __func__));
+ const float *old_default_array = static_cast<const float *>(IDP_Array(default_value));
+ for (int i = 0; i < ui_data->default_array_len; i++) {
+ ui_data->default_array[i] = double(old_default_array[i]);
+ }
+ }
+ else if (default_value->subtype == IDP_DOUBLE) {
+ ui_data->default_array = static_cast<double *>(
+ MEM_malloc_arrayN(array_len, sizeof(double), __func__));
+ memcpy(ui_data->default_array, IDP_Array(default_value), sizeof(double) * array_len);
+ }
+ }
+ else if (ELEM(default_value->type, IDP_DOUBLE, IDP_FLOAT)) {
+ ui_data->default_value = IDP_coerce_to_double_or_zero(default_value);
+ }
+ }
+}
+
+static void version_idproperty_move_data_string(IDPropertyUIDataString *ui_data,
+ const IDProperty *prop_ui_data)
+{
+ IDProperty *default_value = IDP_GetPropertyFromGroup(prop_ui_data, "default");
+ if (default_value != nullptr && default_value->type == IDP_STRING) {
+ ui_data->default_value = BLI_strdup(IDP_String(default_value));
+ }
+}
+
+static void version_idproperty_ui_data(IDProperty *idprop_group)
+{
+ if (idprop_group ==
+ nullptr) { /* nullptr check here to reduce verbosity of calls to this function. */
+ return;
+ }
+
+ IDProperty *ui_container = idproperty_find_ui_container(idprop_group);
+ if (ui_container == nullptr) {
+ return;
+ }
+
+ LISTBASE_FOREACH (IDProperty *, prop, &idprop_group->data.group) {
+ IDProperty *prop_ui_data = IDP_GetPropertyFromGroup(ui_container, prop->name);
+ if (prop_ui_data == nullptr) {
+ continue;
+ }
+
+ if (!IDP_ui_data_supported(prop)) {
+ continue;
+ }
+
+ IDPropertyUIData *ui_data = IDP_ui_data_ensure(prop);
+
+ IDProperty *subtype = IDP_GetPropertyFromGroup(prop_ui_data, "subtype");
+ if (subtype != nullptr && subtype->type == IDP_STRING) {
+ const char *subtype_string = IDP_String(subtype);
+ int result = PROP_NONE;
+ RNA_enum_value_from_id(rna_enum_property_subtype_items, subtype_string, &result);
+ ui_data->rna_subtype = result;
+ }
+
+ IDProperty *description = IDP_GetPropertyFromGroup(prop_ui_data, "description");
+ if (description != nullptr && description->type == IDP_STRING) {
+ ui_data->description = BLI_strdup(IDP_String(description));
+ }
+
+ /* Type specific data. */
+ switch (IDP_ui_data_type(prop)) {
+ case IDP_UI_DATA_TYPE_STRING:
+ version_idproperty_move_data_string((IDPropertyUIDataString *)ui_data, prop_ui_data);
+ break;
+ case IDP_UI_DATA_TYPE_ID:
+ break;
+ case IDP_UI_DATA_TYPE_INT:
+ version_idproperty_move_data_int((IDPropertyUIDataInt *)ui_data, prop_ui_data);
+ break;
+ case IDP_UI_DATA_TYPE_FLOAT:
+ version_idproperty_move_data_float((IDPropertyUIDataFloat *)ui_data, prop_ui_data);
+ break;
+ case IDP_UI_DATA_TYPE_UNSUPPORTED:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ IDP_FreeFromGroup(ui_container, prop_ui_data);
+ }
+
+ IDP_FreeFromGroup(idprop_group, ui_container);
+}
+
+static void do_versions_idproperty_bones_recursive(Bone *bone)
+{
+ version_idproperty_ui_data(bone->prop);
+ LISTBASE_FOREACH (Bone *, child_bone, &bone->childbase) {
+ do_versions_idproperty_bones_recursive(child_bone);
+ }
+}
+
+static void do_versions_idproperty_seq_recursive(ListBase *seqbase)
+{
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ version_idproperty_ui_data(seq->prop);
+ if (seq->type == SEQ_TYPE_META) {
+ do_versions_idproperty_seq_recursive(&seq->seqbase);
+ }
+ }
+}
+
+/**
+ * For every data block that supports them, initialize the new IDProperty UI data struct based on
+ * the old more complicated storage. Assumes only the top level of IDProperties below the parent
+ * group had UI data in a "_RNA_UI" group.
+ *
+ * \note The following IDProperty groups in DNA aren't exposed in the UI or are runtime-only, so
+ * they don't have UI data: wmOperator, bAddon, bUserMenuItem_Op, wmKeyMapItem, wmKeyConfigPref,
+ * uiList, FFMpegCodecData, View3DShading, bToolRef, TimeMarker, ViewLayer, bPoseChannel.
+ */
+static void do_versions_idproperty_ui_data(Main *bmain)
+{
+ /* ID data. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ IDProperty *idprop_group = IDP_GetProperties(id, false);
+ version_idproperty_ui_data(idprop_group);
+ }
+ FOREACH_MAIN_ID_END;
+
+ /* Bones. */
+ LISTBASE_FOREACH (bArmature *, armature, &bmain->armatures) {
+ LISTBASE_FOREACH (Bone *, bone, &armature->bonebase) {
+ do_versions_idproperty_bones_recursive(bone);
+ }
+ }
+
+ /* Nodes and node sockets. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ version_idproperty_ui_data(node->prop);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->inputs) {
+ version_idproperty_ui_data(socket->prop);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->outputs) {
+ version_idproperty_ui_data(socket->prop);
+ }
+ }
+
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ /* The UI data from exposed node modifier properties is just copied from the corresponding node
+ * group, but the copying only runs when necessary, so we still need to version data here. */
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ version_idproperty_ui_data(nmd->settings.properties);
+ }
+ }
+
+ /* Object post bones. */
+ if (ob->type == OB_ARMATURE && ob->pose != nullptr) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ version_idproperty_ui_data(pchan->prop);
+ }
+ }
+ }
+
+ /* Sequences. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->ed != nullptr) {
+ do_versions_idproperty_seq_recursive(&scene->ed->seqbase);
+ }
+ }
+}
+
+static void sort_linked_ids(Main *bmain)
+{
+ ListBase *lb;
+ FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
+ ListBase temp_list;
+ BLI_listbase_clear(&temp_list);
+ LISTBASE_FOREACH_MUTABLE (ID *, id, lb) {
+ if (ID_IS_LINKED(id)) {
+ BLI_remlink(lb, id);
+ BLI_addtail(&temp_list, id);
+ id_sort_by_name(&temp_list, id, nullptr);
+ }
+ }
+ BLI_movelisttolist(lb, &temp_list);
+ }
+ FOREACH_MAIN_LISTBASE_END;
+}
+
+static void assert_sorted_ids(Main *bmain)
+{
+#ifndef NDEBUG
+ ListBase *lb;
+ FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
+ ID *id_prev = nullptr;
+ LISTBASE_FOREACH (ID *, id, lb) {
+ if (id_prev == nullptr) {
+ continue;
+ }
+ BLI_assert(id_prev->lib != id->lib || BLI_strcasecmp(id_prev->name, id->name) < 0);
+ }
+ }
+ FOREACH_MAIN_LISTBASE_END;
+#else
+ UNUSED_VARS_NDEBUG(bmain);
+#endif
+}
+
+static void move_vertex_group_names_to_object_data(Main *bmain)
+{
+ LISTBASE_FOREACH (Object *, object, &bmain->objects) {
+ if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
+ ListBase *new_defbase = BKE_object_defgroup_list_mutable(object);
+
+ /* Choose the longest vertex group name list among all linked duplicates. */
+ if (BLI_listbase_count(&object->defbase) < BLI_listbase_count(new_defbase)) {
+ BLI_freelistN(&object->defbase);
+ }
+ else {
+ /* Clear the list in case the it was already assigned from another object. */
+ BLI_freelistN(new_defbase);
+ *new_defbase = object->defbase;
+ BKE_object_defgroup_active_index_set(object, object->actdef);
+ }
+ }
+ }
+}
+
+static void do_versions_sequencer_speed_effect_recursive(Scene *scene, const ListBase *seqbase)
+{
+ /* Old SpeedControlVars->flags. */
+#define SEQ_SPEED_INTEGRATE (1 << 0)
+#define SEQ_SPEED_COMPRESS_IPO_Y (1 << 2)
+
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (seq->type == SEQ_TYPE_SPEED) {
+ SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
+ const char *substr = nullptr;
+ float globalSpeed = v->globalSpeed;
+ if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
+ if (globalSpeed == 1.0f) {
+ v->speed_control_type = SEQ_SPEED_STRETCH;
+ }
+ else {
+ v->speed_control_type = SEQ_SPEED_MULTIPLY;
+ v->speed_fader = globalSpeed *
+ (float(seq->seq1->len) /
+ max_ff(float(SEQ_time_right_handle_frame_get(scene, seq->seq1) -
+ seq->seq1->start),
+ 1.0f));
+ }
+ }
+ else if (v->flags & SEQ_SPEED_INTEGRATE) {
+ v->speed_control_type = SEQ_SPEED_MULTIPLY;
+ v->speed_fader = seq->speed_fader * globalSpeed;
+ }
+ else if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) {
+ globalSpeed *= 100.0f;
+ v->speed_control_type = SEQ_SPEED_LENGTH;
+ v->speed_fader_length = seq->speed_fader * globalSpeed;
+ substr = "speed_length";
+ }
+ else {
+ v->speed_control_type = SEQ_SPEED_FRAME_NUMBER;
+ v->speed_fader_frame_number = int(seq->speed_fader * globalSpeed);
+ substr = "speed_frame_number";
+ }
+
+ v->flags &= ~(SEQ_SPEED_INTEGRATE | SEQ_SPEED_COMPRESS_IPO_Y);
+
+ if (substr || globalSpeed != 1.0f) {
+ FCurve *fcu = id_data_find_fcurve(
+ &scene->id, seq, &RNA_Sequence, "speed_factor", 0, nullptr);
+ if (fcu) {
+ if (globalSpeed != 1.0f) {
+ for (int i = 0; i < fcu->totvert; i++) {
+ BezTriple *bezt = &fcu->bezt[i];
+ bezt->vec[0][1] *= globalSpeed;
+ bezt->vec[1][1] *= globalSpeed;
+ bezt->vec[2][1] *= globalSpeed;
+ }
+ }
+ if (substr) {
+ char *new_path = BLI_str_replaceN(fcu->rna_path, "speed_factor", substr);
+ MEM_freeN(fcu->rna_path);
+ fcu->rna_path = new_path;
+ }
+ }
+ }
+ }
+ else if (seq->type == SEQ_TYPE_META) {
+ do_versions_sequencer_speed_effect_recursive(scene, &seq->seqbase);
+ }
+ }
+
+#undef SEQ_SPEED_INTEGRATE
+#undef SEQ_SPEED_COMPRESS_IPO_Y
+}
+
+static bool do_versions_sequencer_color_tags(Sequence *seq, void * /*user_data*/)
+{
+ seq->color_tag = SEQUENCE_COLOR_NONE;
+ return true;
+}
+
+static bool do_versions_sequencer_color_balance_sop(Sequence *seq, void * /*user_data*/)
+{
+ LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) {
+ if (smd->type == seqModifierType_ColorBalance) {
+ StripColorBalance *cb = &((ColorBalanceModifierData *)smd)->color_balance;
+ cb->method = SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN;
+ for (int i = 0; i < 3; i++) {
+ copy_v3_fl(cb->slope, 1.0f);
+ copy_v3_fl(cb->offset, 1.0f);
+ copy_v3_fl(cb->power, 1.0f);
+ }
+ }
+ }
+ return true;
+}
+
+static bNodeLink *find_connected_link(bNodeTree *ntree, bNodeSocket *in_socket)
+{
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->tosock == in_socket) {
+ return link;
+ }
+ }
+ return nullptr;
+}
+
+static void add_realize_instances_before_socket(bNodeTree *ntree,
+ bNode *node,
+ bNodeSocket *geometry_socket)
+{
+ BLI_assert(geometry_socket->type == SOCK_GEOMETRY);
+ bNodeLink *link = find_connected_link(ntree, geometry_socket);
+ if (link == nullptr) {
+ return;
+ }
+
+ /* If the realize instances node is already before this socket, no need to continue. */
+ if (link->fromnode->type == GEO_NODE_REALIZE_INSTANCES) {
+ return;
+ }
+
+ bNode *realize_node = nodeAddStaticNode(nullptr, ntree, GEO_NODE_REALIZE_INSTANCES);
+ realize_node->parent = node->parent;
+ realize_node->locx = node->locx - 100;
+ realize_node->locy = node->locy;
+ nodeAddLink(ntree,
+ link->fromnode,
+ link->fromsock,
+ realize_node,
+ static_cast<bNodeSocket *>(realize_node->inputs.first));
+ link->fromnode = realize_node;
+ link->fromsock = static_cast<bNodeSocket *>(realize_node->outputs.first);
+}
+
+/**
+ * If a node used to realize instances implicitly and will no longer do so in 3.0, add a "Realize
+ * Instances" node in front of it to avoid changing behavior. Don't do this if the node will be
+ * replaced anyway though.
+ */
+static void version_geometry_nodes_add_realize_instance_nodes(bNodeTree *ntree)
+{
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
+ if (ELEM(node->type,
+ GEO_NODE_CAPTURE_ATTRIBUTE,
+ GEO_NODE_SEPARATE_COMPONENTS,
+ GEO_NODE_CONVEX_HULL,
+ GEO_NODE_CURVE_LENGTH,
+ GEO_NODE_MESH_BOOLEAN,
+ GEO_NODE_FILLET_CURVE,
+ GEO_NODE_RESAMPLE_CURVE,
+ GEO_NODE_CURVE_TO_MESH,
+ GEO_NODE_TRIM_CURVE,
+ GEO_NODE_REPLACE_MATERIAL,
+ GEO_NODE_SUBDIVIDE_MESH,
+ GEO_NODE_TRIANGULATE)) {
+ bNodeSocket *geometry_socket = static_cast<bNodeSocket *>(node->inputs.first);
+ add_realize_instances_before_socket(ntree, node, geometry_socket);
+ }
+ /* Also realize instances for the profile input of the curve to mesh node. */
+ if (node->type == GEO_NODE_CURVE_TO_MESH) {
+ bNodeSocket *profile_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
+ add_realize_instances_before_socket(ntree, node, profile_socket);
+ }
+ }
+}
+
+/**
+ * The geometry nodes modifier used to realize instances for the next modifier implicitly. Now it
+ * is done with the realize instances node. It also used to convert meshes to point clouds
+ * automatically, which is also now done with a specific node.
+ */
+static bNodeTree *add_realize_node_tree(Main *bmain)
+{
+ bNodeTree *node_tree = ntreeAddTree(bmain, "Realize Instances 2.93 Legacy", "GeometryNodeTree");
+
+ ntreeAddSocketInterface(node_tree, SOCK_IN, "NodeSocketGeometry", "Geometry");
+ ntreeAddSocketInterface(node_tree, SOCK_OUT, "NodeSocketGeometry", "Geometry");
+
+ bNode *group_input = nodeAddStaticNode(nullptr, node_tree, NODE_GROUP_INPUT);
+ group_input->locx = -400.0f;
+ bNode *group_output = nodeAddStaticNode(nullptr, node_tree, NODE_GROUP_OUTPUT);
+ group_output->locx = 500.0f;
+ group_output->flag |= NODE_DO_OUTPUT;
+
+ bNode *join = nodeAddStaticNode(nullptr, node_tree, GEO_NODE_JOIN_GEOMETRY);
+ join->locx = group_output->locx - 175.0f;
+ join->locy = group_output->locy;
+ bNode *conv = nodeAddStaticNode(nullptr, node_tree, GEO_NODE_POINTS_TO_VERTICES);
+ conv->locx = join->locx - 175.0f;
+ conv->locy = join->locy - 70.0;
+ bNode *separate = nodeAddStaticNode(nullptr, node_tree, GEO_NODE_SEPARATE_COMPONENTS);
+ separate->locx = join->locx - 350.0f;
+ separate->locy = join->locy + 50.0f;
+ bNode *realize = nodeAddStaticNode(nullptr, node_tree, GEO_NODE_REALIZE_INSTANCES);
+ realize->locx = separate->locx - 200.0f;
+ realize->locy = join->locy;
+
+ nodeAddLink(node_tree,
+ group_input,
+ static_cast<bNodeSocket *>(group_input->outputs.first),
+ realize,
+ static_cast<bNodeSocket *>(realize->inputs.first));
+ nodeAddLink(node_tree,
+ realize,
+ static_cast<bNodeSocket *>(realize->outputs.first),
+ separate,
+ static_cast<bNodeSocket *>(separate->inputs.first));
+ nodeAddLink(node_tree,
+ conv,
+ static_cast<bNodeSocket *>(conv->outputs.first),
+ join,
+ static_cast<bNodeSocket *>(join->inputs.first));
+ nodeAddLink(node_tree,
+ separate,
+ static_cast<bNodeSocket *>(BLI_findlink(&separate->outputs, 3)),
+ join,
+ static_cast<bNodeSocket *>(join->inputs.first));
+ nodeAddLink(node_tree,
+ separate,
+ static_cast<bNodeSocket *>(BLI_findlink(&separate->outputs, 1)),
+ conv,
+ static_cast<bNodeSocket *>(conv->inputs.first));
+ nodeAddLink(node_tree,
+ separate,
+ static_cast<bNodeSocket *>(BLI_findlink(&separate->outputs, 2)),
+ join,
+ static_cast<bNodeSocket *>(join->inputs.first));
+ nodeAddLink(node_tree,
+ separate,
+ static_cast<bNodeSocket *>(separate->outputs.first),
+ join,
+ static_cast<bNodeSocket *>(join->inputs.first));
+ nodeAddLink(node_tree,
+ join,
+ static_cast<bNodeSocket *>(join->outputs.first),
+ group_output,
+ static_cast<bNodeSocket *>(group_output->inputs.first));
+
+ LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
+ nodeSetSelected(node, false);
+ }
+
+ version_socket_update_is_used(node_tree);
+ return node_tree;
+}
+
+static void seq_speed_factor_fix_rna_path(Sequence *seq, ListBase *fcurves)
+{
+ char name_esc[(sizeof(seq->name) - 2) * 2];
+ BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
+ char *path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].pitch", name_esc);
+ FCurve *fcu = BKE_fcurve_find(fcurves, path, 0);
+ if (fcu != nullptr) {
+ MEM_freeN(fcu->rna_path);
+ fcu->rna_path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].speed_factor", name_esc);
+ }
+ MEM_freeN(path);
+}
+
+static bool seq_speed_factor_set(Sequence *seq, void *user_data)
+{
+ const Scene *scene = static_cast<const Scene *>(user_data);
+ if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ /* Move `pitch` animation to `speed_factor` */
+ if (scene->adt && scene->adt->action) {
+ seq_speed_factor_fix_rna_path(seq, &scene->adt->action->curves);
+ }
+ if (scene->adt && !BLI_listbase_is_empty(&scene->adt->drivers)) {
+ seq_speed_factor_fix_rna_path(seq, &scene->adt->drivers);
+ }
+
+ seq->speed_factor = seq->pitch;
+ }
+ else {
+ seq->speed_factor = 1.0f;
+ }
+ return true;
+}
+
+static void version_geometry_nodes_replace_transfer_attribute_node(bNodeTree *ntree)
+{
+ using namespace blender;
+ /* Otherwise `ntree->typeInfo` is null. */
+ ntreeSetTypes(nullptr, ntree);
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_TRANSFER_ATTRIBUTE_DEPRECATED) {
+ continue;
+ }
+ bNodeSocket *old_geometry_socket = nodeFindSocket(node, SOCK_IN, "Source");
+ const NodeGeometryTransferAttribute *storage = (const NodeGeometryTransferAttribute *)
+ node->storage;
+ switch (storage->mode) {
+ case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: {
+ bNode *sample_nearest_surface = nodeAddStaticNode(
+ nullptr, ntree, GEO_NODE_SAMPLE_NEAREST_SURFACE);
+ sample_nearest_surface->parent = node->parent;
+ sample_nearest_surface->custom1 = storage->data_type;
+ sample_nearest_surface->locx = node->locx;
+ sample_nearest_surface->locy = node->locy;
+ static auto socket_remap = []() {
+ Map<std::string, std::string> map;
+ map.add_new("Attribute", "Value_Vector");
+ map.add_new("Attribute_001", "Value_Float");
+ map.add_new("Attribute_002", "Value_Color");
+ map.add_new("Attribute_003", "Value_Bool");
+ map.add_new("Attribute_004", "Value_Int");
+ map.add_new("Source", "Mesh");
+ map.add_new("Source Position", "Sample Position");
+ return map;
+ }();
+ node_tree_relink_with_socket_id_map(*ntree, *node, *sample_nearest_surface, socket_remap);
+ break;
+ }
+ case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST: {
+ /* These domains weren't supported by the index transfer mode, but were selectable. */
+ const eAttrDomain domain = ELEM(storage->domain, ATTR_DOMAIN_INSTANCE, ATTR_DOMAIN_CURVE) ?
+ ATTR_DOMAIN_POINT :
+ eAttrDomain(storage->domain);
+
+ /* Use a sample index node to retrieve the data with this node's index output. */
+ bNode *sample_index = nodeAddStaticNode(nullptr, ntree, GEO_NODE_SAMPLE_INDEX);
+ NodeGeometrySampleIndex *sample_storage = static_cast<NodeGeometrySampleIndex *>(
+ sample_index->storage);
+ sample_storage->data_type = storage->data_type;
+ sample_storage->domain = domain;
+ sample_index->parent = node->parent;
+ sample_index->locx = node->locx + 25.0f;
+ sample_index->locy = node->locy;
+ if (old_geometry_socket->link) {
+ nodeAddLink(ntree,
+ old_geometry_socket->link->fromnode,
+ old_geometry_socket->link->fromsock,
+ sample_index,
+ nodeFindSocket(sample_index, SOCK_IN, "Geometry"));
+ }
+
+ bNode *sample_nearest = nodeAddStaticNode(nullptr, ntree, GEO_NODE_SAMPLE_NEAREST);
+ sample_nearest->parent = node->parent;
+ sample_nearest->custom1 = storage->data_type;
+ sample_nearest->custom2 = domain;
+ sample_nearest->locx = node->locx - 25.0f;
+ sample_nearest->locy = node->locy;
+ if (old_geometry_socket->link) {
+ nodeAddLink(ntree,
+ old_geometry_socket->link->fromnode,
+ old_geometry_socket->link->fromsock,
+ sample_nearest,
+ nodeFindSocket(sample_nearest, SOCK_IN, "Geometry"));
+ }
+ static auto sample_nearest_remap = []() {
+ Map<std::string, std::string> map;
+ map.add_new("Source Position", "Sample Position");
+ return map;
+ }();
+ node_tree_relink_with_socket_id_map(*ntree, *node, *sample_nearest, sample_nearest_remap);
+
+ static auto sample_index_remap = []() {
+ Map<std::string, std::string> map;
+ map.add_new("Attribute", "Value_Vector");
+ map.add_new("Attribute_001", "Value_Float");
+ map.add_new("Attribute_002", "Value_Color");
+ map.add_new("Attribute_003", "Value_Bool");
+ map.add_new("Attribute_004", "Value_Int");
+ map.add_new("Source Position", "Sample Position");
+ return map;
+ }();
+ node_tree_relink_with_socket_id_map(*ntree, *node, *sample_index, sample_index_remap);
+
+ nodeAddLink(ntree,
+ sample_nearest,
+ nodeFindSocket(sample_nearest, SOCK_OUT, "Index"),
+ sample_index,
+ nodeFindSocket(sample_index, SOCK_IN, "Index"));
+ break;
+ }
+ case GEO_NODE_ATTRIBUTE_TRANSFER_INDEX: {
+ bNode *sample_index = nodeAddStaticNode(nullptr, ntree, GEO_NODE_SAMPLE_INDEX);
+ NodeGeometrySampleIndex *sample_storage = static_cast<NodeGeometrySampleIndex *>(
+ sample_index->storage);
+ sample_storage->data_type = storage->data_type;
+ sample_storage->domain = storage->domain;
+ sample_storage->clamp = 1;
+ sample_index->parent = node->parent;
+ sample_index->locx = node->locx;
+ sample_index->locy = node->locy;
+ const bool index_was_linked = nodeFindSocket(node, SOCK_IN, "Index")->link != nullptr;
+ static auto socket_remap = []() {
+ Map<std::string, std::string> map;
+ map.add_new("Attribute", "Value_Vector");
+ map.add_new("Attribute_001", "Value_Float");
+ map.add_new("Attribute_002", "Value_Color");
+ map.add_new("Attribute_003", "Value_Bool");
+ map.add_new("Attribute_004", "Value_Int");
+ map.add_new("Source", "Geometry");
+ map.add_new("Index", "Index");
+ return map;
+ }();
+ node_tree_relink_with_socket_id_map(*ntree, *node, *sample_index, socket_remap);
+
+ if (!index_was_linked) {
+ /* Add an index input node, since the new node doesn't use an implicit input. */
+ bNode *index = nodeAddStaticNode(nullptr, ntree, GEO_NODE_INPUT_INDEX);
+ index->parent = node->parent;
+ index->locx = node->locx - 25.0f;
+ index->locy = node->locy - 25.0f;
+ nodeAddLink(ntree,
+ index,
+ nodeFindSocket(index, SOCK_OUT, "Index"),
+ sample_index,
+ nodeFindSocket(sample_index, SOCK_IN, "Index"));
+ }
+ break;
+ }
+ }
+ /* The storage must be freed manually because the node type isn't defined anymore. */
+ MEM_freeN(node->storage);
+ nodeRemoveNode(nullptr, ntree, node, false);
+ }
+}
+
+void do_versions_after_linking_300(Main *bmain, ReportList * /*reports*/)
+{
+ if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
+ /* Set zero user text objects to have a fake user. */
+ LISTBASE_FOREACH (Text *, text, &bmain->texts) {
+ if (text->id.us == 0) {
+ id_fake_user_set(&text->id);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 3)) {
+ sort_linked_ids(bmain);
+ assert_sorted_ids(bmain);
+ }
+
+ if (MAIN_VERSION_ATLEAST(bmain, 300, 3)) {
+ assert_sorted_ids(bmain);
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 11)) {
+ move_vertex_group_names_to_object_data(bmain);
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 13)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->ed != nullptr) {
+ do_versions_sequencer_speed_effect_recursive(scene, &scene->ed->seqbase);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 25)) {
+ version_node_socket_index_animdata(bmain, NTREE_SHADER, SH_NODE_BSDF_PRINCIPLED, 4, 2, 25);
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 26)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *tool_settings = scene->toolsettings;
+ ImagePaintSettings *imapaint = &tool_settings->imapaint;
+ if (imapaint->canvas != nullptr &&
+ ELEM(imapaint->canvas->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
+ imapaint->canvas = nullptr;
+ }
+ if (imapaint->stencil != nullptr &&
+ ELEM(imapaint->stencil->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
+ imapaint->stencil = nullptr;
+ }
+ if (imapaint->clone != nullptr &&
+ ELEM(imapaint->clone->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
+ imapaint->clone = nullptr;
+ }
+ }
+
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->clone.image != nullptr &&
+ ELEM(brush->clone.image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
+ brush->clone.image = nullptr;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 28)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_geometry_nodes_add_realize_instance_nodes(ntree);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 30)) {
+ do_versions_idproperty_ui_data(bmain);
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 32)) {
+ /* Update Switch Node Non-Fields switch input to Switch_001. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->tonode->type == GEO_NODE_SWITCH) {
+ if (STREQ(link->tosock->identifier, "Switch")) {
+ bNode *to_node = link->tonode;
+
+ uint8_t mode = ((NodeSwitch *)to_node->storage)->input_type;
+ if (ELEM(mode,
+ SOCK_GEOMETRY,
+ SOCK_OBJECT,
+ SOCK_COLLECTION,
+ SOCK_TEXTURE,
+ SOCK_MATERIAL)) {
+ link->tosock = link->tosock->next;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 33)) {
+ /* This was missing from #move_vertex_group_names_to_object_data. */
+ LISTBASE_FOREACH (Object *, object, &bmain->objects) {
+ if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
+ /* This uses the fact that the active vertex group index starts counting at 1. */
+ if (BKE_object_defgroup_active_index_get(object) == 0) {
+ BKE_object_defgroup_active_index_set(object, object->actdef);
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 35)) {
+ /* Add a new modifier to realize instances from previous modifiers.
+ * Previously that was done automatically by geometry nodes. */
+ bNodeTree *realize_instances_node_tree = nullptr;
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH_MUTABLE (ModifierData *, md, &ob->modifiers) {
+ if (md->type != eModifierType_Nodes) {
+ continue;
+ }
+ if (md->next == nullptr) {
+ break;
+ }
+ if (md->next->type == eModifierType_Nodes) {
+ continue;
+ }
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group == nullptr) {
+ continue;
+ }
+
+ NodesModifierData *new_nmd = (NodesModifierData *)BKE_modifier_new(eModifierType_Nodes);
+ STRNCPY(new_nmd->modifier.name, "Realize Instances 2.93 Legacy");
+ BKE_modifier_unique_name(&ob->modifiers, &new_nmd->modifier);
+ BLI_insertlinkafter(&ob->modifiers, md, new_nmd);
+ if (realize_instances_node_tree == nullptr) {
+ realize_instances_node_tree = add_realize_node_tree(bmain);
+ }
+ new_nmd->node_group = realize_instances_node_tree;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 37)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_BOUNDING_BOX) {
+ bNodeSocket *geometry_socket = static_cast<bNodeSocket *>(node->inputs.first);
+ add_realize_instances_before_socket(ntree, node, geometry_socket);
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 6)) {
+ { /* Ensure driver variable names are unique within the driver. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == nullptr) {
+ continue;
+ }
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
+ ChannelDriver *driver = fcu->driver;
+ /* Ensure the uniqueness front to back. Given a list of identically
+ * named variables, the last one gets to keep its original name. This
+ * matches the evaluation order, and thus shouldn't change the evaluated
+ * value of the driver expression. */
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ BLI_uniquename(&driver->variables,
+ dvar,
+ dvar->name,
+ '_',
+ offsetof(DriverVar, name),
+ sizeof(dvar->name));
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ /* Ensure tiled image sources contain a UDIM token. */
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ if (ima->source == IMA_SRC_TILED) {
+ char *filename = (char *)BLI_path_basename(ima->filepath);
+ BKE_image_ensure_tile_token(filename);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 14)) {
+ /* Sequencer channels region. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype != SPACE_SEQ) {
+ continue;
+ }
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ sseq->flag |= SEQ_CLAMP_VIEW;
+
+ if (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
+ continue;
+ }
+
+ ARegion *timeline_region = BKE_region_find_in_listbase_by_type(regionbase,
+ RGN_TYPE_WINDOW);
+
+ if (timeline_region == nullptr) {
+ continue;
+ }
+
+ timeline_region->v2d.cur.ymax = 8.5f;
+ timeline_region->v2d.align &= ~V2D_ALIGN_NO_NEG_Y;
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 5)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ Editing *ed = SEQ_editing_get(scene);
+ if (ed == nullptr) {
+ continue;
+ }
+ SEQ_for_each_callback(&ed->seqbase, seq_speed_factor_set, scene);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 6)) {
+ /* In the Dope Sheet, for every mode other than Timeline, open the Properties panel. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype != SPACE_ACTION) {
+ continue;
+ }
+
+ /* Skip the timeline, it shouldn't get its Properties panel opened. */
+ SpaceAction *saction = (SpaceAction *)sl;
+ if (saction->mode == SACTCONT_TIMELINE) {
+ continue;
+ }
+
+ const bool is_first_space = sl == area->spacedata.first;
+ ListBase *regionbase = is_first_space ? &area->regionbase : &sl->regionbase;
+ ARegion *region = BKE_region_find_in_listbase_by_type(regionbase, RGN_TYPE_UI);
+ if (region == nullptr) {
+ continue;
+ }
+
+ region->flag &= ~RGN_FLAG_HIDDEN;
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 304, 1)) {
+ /* Split the transfer attribute node into multiple smaller nodes. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_geometry_nodes_replace_transfer_attribute_node(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - #blo_do_versions_300 in this file.
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+ }
+}
+
+static void version_switch_node_input_prefix(Main *bmain)
+{
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_SWITCH) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ /* Skip the "switch" socket. */
+ if (socket == node->inputs.first) {
+ continue;
+ }
+ strcpy(socket->name, socket->name[0] == 'A' ? "False" : "True");
+
+ /* Replace "A" and "B", but keep the unique number suffix at the end. */
+ char number_suffix[8];
+ BLI_strncpy(number_suffix, socket->identifier + 1, sizeof(number_suffix));
+ strcpy(socket->identifier, socket->name);
+ strcat(socket->identifier, number_suffix);
+ }
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+}
+
+static bool replace_bbone_len_scale_rnapath(char **p_old_path, int *p_index)
+{
+ char *old_path = *p_old_path;
+
+ if (old_path == nullptr) {
+ return false;
+ }
+
+ int len = strlen(old_path);
+
+ if (BLI_str_endswith(old_path, ".bbone_curveiny") ||
+ BLI_str_endswith(old_path, ".bbone_curveouty")) {
+ old_path[len - 1] = 'z';
+ return true;
+ }
+
+ if (BLI_str_endswith(old_path, ".bbone_scaleinx") ||
+ BLI_str_endswith(old_path, ".bbone_scaleiny") ||
+ BLI_str_endswith(old_path, ".bbone_scaleoutx") ||
+ BLI_str_endswith(old_path, ".bbone_scaleouty")) {
+ int index = (old_path[len - 1] == 'y' ? 2 : 0);
+
+ old_path[len - 1] = 0;
+
+ if (p_index) {
+ *p_index = index;
+ }
+ else {
+ *p_old_path = BLI_sprintfN("%s[%d]", old_path, index);
+ MEM_freeN(old_path);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static void do_version_bbone_len_scale_fcurve_fix(FCurve *fcu)
+{
+ /* Update driver variable paths. */
+ if (fcu->driver) {
+ LISTBASE_FOREACH (DriverVar *, dvar, &fcu->driver->variables) {
+ DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
+ replace_bbone_len_scale_rnapath(&dtar->rna_path, nullptr);
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+
+ /* Update F-Curve's path. */
+ replace_bbone_len_scale_rnapath(&fcu->rna_path, &fcu->array_index);
+}
+
+static void do_version_bbone_len_scale_animdata_cb(ID * /*id*/,
+ AnimData *adt,
+ void * /*wrapper_data*/)
+{
+ LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &adt->drivers) {
+ do_version_bbone_len_scale_fcurve_fix(fcu);
+ }
+}
+
+static void do_version_bones_bbone_len_scale(ListBase *lb)
+{
+ LISTBASE_FOREACH (Bone *, bone, lb) {
+ if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ bone->bbone_flag |= BBONE_ADD_PARENT_END_ROLL;
+ }
+
+ copy_v3_fl3(bone->scale_in, bone->scale_in_x, 1.0f, bone->scale_in_z);
+ copy_v3_fl3(bone->scale_out, bone->scale_out_x, 1.0f, bone->scale_out_z);
+
+ do_version_bones_bbone_len_scale(&bone->childbase);
+ }
+}
+
+static void do_version_constraints_spline_ik_joint_bindings(ListBase *lb)
+{
+ /* Binding array data could be freed without properly resetting its size data. */
+ LISTBASE_FOREACH (bConstraint *, con, lb) {
+ if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+ if (data->points == nullptr) {
+ data->numpoints = 0;
+ }
+ }
+ }
+}
+
+static bNodeSocket *do_version_replace_float_size_with_vector(bNodeTree *ntree,
+ bNode *node,
+ bNodeSocket *socket)
+{
+ const bNodeSocketValueFloat *socket_value = (const bNodeSocketValueFloat *)socket->default_value;
+ const float old_value = socket_value->value;
+ nodeRemoveSocket(ntree, node, socket);
+ bNodeSocket *new_socket = nodeAddSocket(
+ ntree, node, SOCK_IN, nodeStaticSocketType(SOCK_VECTOR, PROP_TRANSLATION), "Size", "Size");
+ bNodeSocketValueVector *value_vector = (bNodeSocketValueVector *)new_socket->default_value;
+ copy_v3_fl(value_vector->value, old_value);
+ return new_socket;
+}
+
+static bool seq_transform_origin_set(Sequence *seq, void * /*user_data*/)
+{
+ StripTransform *transform = seq->strip->transform;
+ if (seq->strip->transform != nullptr) {
+ transform->origin[0] = transform->origin[1] = 0.5f;
+ }
+ return true;
+}
+
+static bool seq_transform_filter_set(Sequence *seq, void * /*user_data*/)
+{
+ StripTransform *transform = seq->strip->transform;
+ if (seq->strip->transform != nullptr) {
+ transform->filter = SEQ_TRANSFORM_FILTER_BILINEAR;
+ }
+ return true;
+}
+
+static bool seq_meta_channels_ensure(Sequence *seq, void * /*user_data*/)
+{
+ if (seq->type == SEQ_TYPE_META) {
+ SEQ_channels_ensure(&seq->channels);
+ }
+ return true;
+}
+
+static void do_version_subsurface_methods(bNode *node)
+{
+ if (node->type == SH_NODE_SUBSURFACE_SCATTERING) {
+ if (!ELEM(node->custom1, SHD_SUBSURFACE_BURLEY, SHD_SUBSURFACE_RANDOM_WALK)) {
+ node->custom1 = SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS;
+ }
+ }
+ else if (node->type == SH_NODE_BSDF_PRINCIPLED) {
+ if (!ELEM(node->custom2, SHD_SUBSURFACE_BURLEY, SHD_SUBSURFACE_RANDOM_WALK)) {
+ node->custom2 = SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS;
+ }
+ }
+}
+
+static void version_geometry_nodes_add_attribute_input_settings(NodesModifierData *nmd)
+{
+ if (nmd->settings.properties == nullptr) {
+ return;
+ }
+ /* Before versioning the properties, make sure it hasn't been done already. */
+ LISTBASE_FOREACH (const IDProperty *, property, &nmd->settings.properties->data.group) {
+ if (strstr(property->name, "_use_attribute") || strstr(property->name, "_attribute_name")) {
+ return;
+ }
+ }
+
+ LISTBASE_FOREACH_MUTABLE (IDProperty *, property, &nmd->settings.properties->data.group) {
+ if (!ELEM(property->type, IDP_FLOAT, IDP_INT, IDP_ARRAY)) {
+ continue;
+ }
+
+ if (strstr(property->name, "_use_attribute") || strstr(property->name, "_attribute_name")) {
+ continue;
+ }
+
+ char use_attribute_prop_name[MAX_IDPROP_NAME];
+ BLI_snprintf(use_attribute_prop_name,
+ sizeof(use_attribute_prop_name),
+ "%s%s",
+ property->name,
+ "_use_attribute");
+
+ IDPropertyTemplate idprop = {0};
+ IDProperty *use_attribute_prop = IDP_New(IDP_INT, &idprop, use_attribute_prop_name);
+ IDP_AddToGroup(nmd->settings.properties, use_attribute_prop);
+
+ char attribute_name_prop_name[MAX_IDPROP_NAME];
+ BLI_snprintf(attribute_name_prop_name,
+ sizeof(attribute_name_prop_name),
+ "%s%s",
+ property->name,
+ "_attribute_name");
+
+ IDProperty *attribute_prop = IDP_New(IDP_STRING, &idprop, attribute_name_prop_name);
+ IDP_AddToGroup(nmd->settings.properties, attribute_prop);
+ }
+}
+
+/* Copy of the function before the fixes. */
+static void legacy_vec_roll_to_mat3_normalized(const float nor[3],
+ const float roll,
+ float r_mat[3][3])
+{
+ const float SAFE_THRESHOLD = 1.0e-5f; /* theta above this value has good enough precision. */
+ const float CRITICAL_THRESHOLD = 1.0e-9f; /* above this is safe under certain conditions. */
+ const float THRESHOLD_SQUARED = CRITICAL_THRESHOLD * CRITICAL_THRESHOLD;
+
+ const float x = nor[0];
+ const float y = nor[1];
+ const float z = nor[2];
+
+ const float theta = 1.0f + y; /* remapping Y from [-1,+1] to [0,2]. */
+ const float theta_alt = x * x + z * z; /* Helper value for matrix calculations. */
+ float rMatrix[3][3], bMatrix[3][3];
+
+ BLI_ASSERT_UNIT_V3(nor);
+
+ /* When theta is close to zero (nor is aligned close to negative Y Axis),
+ * we have to check we do have non-null X/Z components as well.
+ * Also, due to float precision errors, nor can be (0.0, -0.99999994, 0.0) which results
+ * in theta being close to zero. This will cause problems when theta is used as divisor.
+ */
+ if (theta > SAFE_THRESHOLD || (theta > CRITICAL_THRESHOLD && theta_alt > THRESHOLD_SQUARED)) {
+ /* nor is *not* aligned to negative Y-axis (0,-1,0). */
+
+ bMatrix[0][1] = -x;
+ bMatrix[1][0] = x;
+ bMatrix[1][1] = y;
+ bMatrix[1][2] = z;
+ bMatrix[2][1] = -z;
+
+ if (theta > SAFE_THRESHOLD) {
+ /* nor differs significantly from negative Y axis (0,-1,0): apply the general case. */
+ bMatrix[0][0] = 1 - x * x / theta;
+ bMatrix[2][2] = 1 - z * z / theta;
+ bMatrix[2][0] = bMatrix[0][2] = -x * z / theta;
+ }
+ else {
+ /* nor is close to negative Y axis (0,-1,0): apply the special case. */
+ bMatrix[0][0] = (x + z) * (x - z) / -theta_alt;
+ bMatrix[2][2] = -bMatrix[0][0];
+ bMatrix[2][0] = bMatrix[0][2] = 2.0f * x * z / theta_alt;
+ }
+ }
+ else {
+ /* nor is very close to negative Y axis (0,-1,0): use simple symmetry by Z axis. */
+ unit_m3(bMatrix);
+ bMatrix[0][0] = bMatrix[1][1] = -1.0;
+ }
+
+ /* Make Roll matrix */
+ axis_angle_normalized_to_mat3(rMatrix, nor, roll);
+
+ /* Combine and output result */
+ mul_m3_m3m3(r_mat, rMatrix, bMatrix);
+}
+
+static void correct_bone_roll_value(const float head[3],
+ const float tail[3],
+ const float check_x_axis[3],
+ const float check_y_axis[3],
+ float *r_roll)
+{
+ const float SAFE_THRESHOLD = 1.0e-5f;
+ float vec[3], bone_mat[3][3], vec2[3];
+
+ /* Compute the Y axis vector. */
+ sub_v3_v3v3(vec, tail, head);
+ normalize_v3(vec);
+
+ /* Only correct when in the danger zone. */
+ if (1.0f + vec[1] < SAFE_THRESHOLD * 2 && (vec[0] || vec[2])) {
+ /* Use the armature matrix to double-check if adjustment is needed.
+ * This should minimize issues if the file is bounced back and forth between
+ * 2.92 and 2.91, provided Edit Mode isn't entered on the armature in 2.91. */
+ vec_roll_to_mat3(vec, *r_roll, bone_mat);
+
+ UNUSED_VARS_NDEBUG(check_y_axis);
+ BLI_assert(dot_v3v3(bone_mat[1], check_y_axis) > 0.999f);
+
+ if (dot_v3v3(bone_mat[0], check_x_axis) < 0.999f) {
+ /* Recompute roll using legacy code to interpret the old value. */
+ legacy_vec_roll_to_mat3_normalized(vec, *r_roll, bone_mat);
+ mat3_to_vec_roll(bone_mat, vec2, r_roll);
+ BLI_assert(compare_v3v3(vec, vec2, 0.001f));
+ }
+ }
+}
+
+/* Update the armature Bone roll fields for bones very close to -Y direction. */
+static void do_version_bones_roll(ListBase *lb)
+{
+ LISTBASE_FOREACH (Bone *, bone, lb) {
+ /* Parent-relative orientation (used for posing). */
+ correct_bone_roll_value(
+ bone->head, bone->tail, bone->bone_mat[0], bone->bone_mat[1], &bone->roll);
+
+ /* Absolute orientation (used for Edit mode). */
+ correct_bone_roll_value(
+ bone->arm_head, bone->arm_tail, bone->arm_mat[0], bone->arm_mat[1], &bone->arm_roll);
+
+ do_version_bones_roll(&bone->childbase);
+ }
+}
+
+static void version_geometry_nodes_set_position_node_offset(bNodeTree *ntree)
+{
+ /* Add the new Offset socket. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_SET_POSITION) {
+ continue;
+ }
+ if (BLI_listbase_count(&node->inputs) < 4) {
+ /* The offset socket didn't exist in the file yet. */
+ return;
+ }
+ bNodeSocket *old_offset_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 3));
+ if (old_offset_socket->type == SOCK_VECTOR) {
+ /* Versioning happened already. */
+ return;
+ }
+ /* Change identifier of old socket, so that the there is no name collision. */
+ STRNCPY(old_offset_socket->identifier, "Offset_old");
+ nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_VECTOR, PROP_TRANSLATION, "Offset", "Offset");
+ }
+
+ /* Relink links that were connected to Position while Offset was enabled. */
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->tonode->type != GEO_NODE_SET_POSITION) {
+ continue;
+ }
+ if (!STREQ(link->tosock->identifier, "Position")) {
+ continue;
+ }
+ bNodeSocket *old_offset_socket = static_cast<bNodeSocket *>(
+ BLI_findlink(&link->tonode->inputs, 3));
+ /* This assumes that the offset is not linked to something else. That seems to be a reasonable
+ * assumption, because the node is probably only ever used in one or the other mode. */
+ const bool offset_enabled =
+ ((bNodeSocketValueBoolean *)old_offset_socket->default_value)->value;
+ if (offset_enabled) {
+ /* Relink to new offset socket. */
+ link->tosock = old_offset_socket->next;
+ }
+ }
+
+ /* Remove old Offset socket. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_SET_POSITION) {
+ continue;
+ }
+ bNodeSocket *old_offset_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 3));
+ nodeRemoveSocket(ntree, node, old_offset_socket);
+ }
+}
+
+static void version_node_tree_socket_id_delim(bNodeTree *ntree)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ version_node_socket_id_delim(socket);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ version_node_socket_id_delim(socket);
+ }
+ }
+}
+
+static bool version_fix_seq_meta_range(Sequence *seq, void *user_data)
+{
+ Scene *scene = (Scene *)user_data;
+ if (seq->type == SEQ_TYPE_META) {
+ SEQ_time_update_meta_strip_range(scene, seq);
+ }
+ return true;
+}
+
+static bool version_merge_still_offsets(Sequence *seq, void * /*user_data*/)
+{
+ seq->startofs -= seq->startstill;
+ seq->endofs -= seq->endstill;
+ seq->startstill = 0;
+ seq->endstill = 0;
+ return true;
+}
+
+/* Those `version_liboverride_rnacollections_*` functions mimic the old, pre-3.0 code to find
+ * anchor and source items in the given list of modifiers, constraints etc., using only the
+ * `subitem_local` data of the override property operation.
+ *
+ * Then they convert it into the new, proper `subitem_reference` data for the anchor, and
+ * `subitem_local` for the source.
+ *
+ * NOTE: Here only the stored override ID is available, unlike in the `override_apply` functions.
+ */
+
+static void version_liboverride_rnacollections_insertion_object_constraints(
+ ListBase *constraints, IDOverrideLibraryProperty *op)
+{
+ LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
+ continue;
+ }
+ bConstraint *constraint_anchor = static_cast<bConstraint *>(
+ BLI_listbase_string_or_index_find(constraints,
+ opop->subitem_local_name,
+ offsetof(bConstraint, name),
+ opop->subitem_local_index));
+ bConstraint *constraint_src = constraint_anchor != nullptr ?
+ constraint_anchor->next :
+ static_cast<bConstraint *>(constraints->first);
+
+ if (constraint_src == nullptr) {
+ /* Invalid case, just remove that override property operation. */
+ CLOG_ERROR(&LOG, "Could not find source constraint in stored override data");
+ BKE_lib_override_library_property_operation_delete(op, opop);
+ continue;
+ }
+
+ opop->subitem_reference_name = opop->subitem_local_name;
+ opop->subitem_local_name = BLI_strdup(constraint_src->name);
+ opop->subitem_reference_index = opop->subitem_local_index;
+ opop->subitem_local_index++;
+ }
+}
+
+static void version_liboverride_rnacollections_insertion_object(Object *object)
+{
+ IDOverrideLibrary *liboverride = object->id.override_library;
+ IDOverrideLibraryProperty *op;
+
+ op = BKE_lib_override_library_property_find(liboverride, "modifiers");
+ if (op != nullptr) {
+ LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
+ continue;
+ }
+ ModifierData *mod_anchor = static_cast<ModifierData *>(
+ BLI_listbase_string_or_index_find(&object->modifiers,
+ opop->subitem_local_name,
+ offsetof(ModifierData, name),
+ opop->subitem_local_index));
+ ModifierData *mod_src = mod_anchor != nullptr ?
+ mod_anchor->next :
+ static_cast<ModifierData *>(object->modifiers.first);
+
+ if (mod_src == nullptr) {
+ /* Invalid case, just remove that override property operation. */
+ CLOG_ERROR(&LOG, "Could not find source modifier in stored override data");
+ BKE_lib_override_library_property_operation_delete(op, opop);
+ continue;
+ }
+
+ opop->subitem_reference_name = opop->subitem_local_name;
+ opop->subitem_local_name = BLI_strdup(mod_src->name);
+ opop->subitem_reference_index = opop->subitem_local_index;
+ opop->subitem_local_index++;
+ }
+ }
+
+ op = BKE_lib_override_library_property_find(liboverride, "grease_pencil_modifiers");
+ if (op != nullptr) {
+ LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
+ continue;
+ }
+ GpencilModifierData *gp_mod_anchor = static_cast<GpencilModifierData *>(
+ BLI_listbase_string_or_index_find(&object->greasepencil_modifiers,
+ opop->subitem_local_name,
+ offsetof(GpencilModifierData, name),
+ opop->subitem_local_index));
+ GpencilModifierData *gp_mod_src = gp_mod_anchor != nullptr ?
+ gp_mod_anchor->next :
+ static_cast<GpencilModifierData *>(
+ object->greasepencil_modifiers.first);
+
+ if (gp_mod_src == nullptr) {
+ /* Invalid case, just remove that override property operation. */
+ CLOG_ERROR(&LOG, "Could not find source GP modifier in stored override data");
+ BKE_lib_override_library_property_operation_delete(op, opop);
+ continue;
+ }
+
+ opop->subitem_reference_name = opop->subitem_local_name;
+ opop->subitem_local_name = BLI_strdup(gp_mod_src->name);
+ opop->subitem_reference_index = opop->subitem_local_index;
+ opop->subitem_local_index++;
+ }
+ }
+
+ op = BKE_lib_override_library_property_find(liboverride, "constraints");
+ if (op != nullptr) {
+ version_liboverride_rnacollections_insertion_object_constraints(&object->constraints, op);
+ }
+
+ if (object->pose != nullptr) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ char rna_path[26 + (sizeof(pchan->name) * 2) + 1];
+ char name_esc[sizeof(pchan->name) * 2];
+ BLI_str_escape(name_esc, pchan->name, sizeof(name_esc));
+ SNPRINTF(rna_path, "pose.bones[\"%s\"].constraints", name_esc);
+ op = BKE_lib_override_library_property_find(liboverride, rna_path);
+ if (op != nullptr) {
+ version_liboverride_rnacollections_insertion_object_constraints(&pchan->constraints, op);
+ }
+ }
+ }
+}
+
+static void version_liboverride_rnacollections_insertion_animdata(ID *id)
+{
+ AnimData *anim_data = BKE_animdata_from_id(id);
+ if (anim_data == nullptr) {
+ return;
+ }
+
+ IDOverrideLibrary *liboverride = id->override_library;
+ IDOverrideLibraryProperty *op;
+
+ op = BKE_lib_override_library_property_find(liboverride, "animation_data.nla_tracks");
+ if (op != nullptr) {
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
+ continue;
+ }
+ /* NLA tracks are only referenced by index, which limits possibilities, basically they are
+ * always added at the end of the list, see #rna_NLA_tracks_override_apply.
+ *
+ * This makes things simple here. */
+ opop->subitem_reference_name = opop->subitem_local_name;
+ opop->subitem_local_name = nullptr;
+ opop->subitem_reference_index = opop->subitem_local_index;
+ opop->subitem_local_index++;
+ }
+ }
+}
+
+static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTree *ntree)
+{
+ /* In geometry nodes, replace shader combine/separate color nodes with function nodes */
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case SH_NODE_COMBRGB_LEGACY: {
+ node->type = FN_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "FunctionNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPRGB_LEGACY: {
+ node->type = FN_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "FunctionNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+
+ /* In compositing nodes, replace combine/separate RGBA/HSVA/YCbCrA/YCCA nodes with
+ * combine/separate color */
+ if (ntree->type == NTREE_COMPOSIT) {
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "H", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "S", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "V", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Y", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cb", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cr", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "Y", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "U", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "V", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "H", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "S", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "V", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Y", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cb", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cr", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "Y", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "U", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "V", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "A", "Alpha");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case CMP_NODE_COMBRGBA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBHSVA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBYCCA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
+ storage->ycc_mode = node->custom1;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBYUVA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPRGBA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPHSVA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPYCCA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
+ storage->ycc_mode = node->custom1;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPYUVA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+
+ /* In texture nodes, replace combine/separate RGBA with combine/separate color */
+ if (ntree->type == NTREE_TEXTURE) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case TEX_NODE_COMPOSE_LEGACY: {
+ node->type = TEX_NODE_COMBINE_COLOR;
+ node->custom1 = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "TextureNodeCombineColor");
+ break;
+ }
+ case TEX_NODE_DECOMPOSE_LEGACY: {
+ node->type = TEX_NODE_SEPARATE_COLOR;
+ node->custom1 = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "TextureNodeSeparateColor");
+ break;
+ }
+ }
+ }
+ }
+
+ /* In shader nodes, replace combine/separate RGB/HSV with combine/separate color */
+ if (ntree->type == NTREE_SHADER) {
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "H", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "S", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "V", "Blue");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "H", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "S", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "V", "Blue");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case SH_NODE_COMBRGB_LEGACY: {
+ node->type = SH_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "ShaderNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_COMBHSV_LEGACY: {
+ node->type = SH_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "ShaderNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPRGB_LEGACY: {
+ node->type = SH_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "ShaderNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPHSV_LEGACY: {
+ node->type = SH_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "ShaderNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void versioning_replace_legacy_mix_rgb_node(bNodeTree *ntree)
+{
+ version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Fac", "Factor_Float");
+ version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color1", "A_Color");
+ version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color2", "B_Color");
+ version_node_output_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color", "Result_Color");
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_MIX_RGB_LEGACY) {
+ strcpy(node->idname, "ShaderNodeMix");
+ node->type = SH_NODE_MIX;
+ NodeShaderMix *data = (NodeShaderMix *)MEM_callocN(sizeof(NodeShaderMix), __func__);
+ data->blend_type = node->custom1;
+ data->clamp_result = (node->custom2 & SHD_MIXRGB_CLAMP) ? 1 : 0;
+ data->clamp_factor = 1;
+ data->data_type = SOCK_RGBA;
+ data->factor_mode = NODE_MIX_MODE_UNIFORM;
+ node->storage = data;
+ }
+ }
+}
+
+static void version_fix_image_format_copy(Main *bmain, ImageFormatData *format)
+{
+ /* Fix bug where curves in image format were not properly copied to file output
+ * node, incorrectly sharing a pointer with the scene settings. Copy the data
+ * structure now as it should have been done in the first place. */
+ if (format->view_settings.curve_mapping) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (format != &scene->r.im_format && ELEM(format->view_settings.curve_mapping,
+ scene->view_settings.curve_mapping,
+ scene->r.im_format.view_settings.curve_mapping)) {
+ format->view_settings.curve_mapping = BKE_curvemapping_copy(
+ format->view_settings.curve_mapping);
+ break;
+ }
+ }
+
+ /* Remove any invalid curves with missing data. */
+ if (format->view_settings.curve_mapping->cm[0].curve == nullptr) {
+ BKE_curvemapping_free(format->view_settings.curve_mapping);
+ format->view_settings.curve_mapping = nullptr;
+ format->view_settings.flag &= ~COLORMANAGE_VIEW_USE_CURVES;
+ }
+ }
+}
+
+/* NOLINTNEXTLINE: readability-function-size */
+void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
+{
+ /* The #SCE_SNAP_SEQ flag has been removed in favor of the #SCE_SNAP which can be used for each
+ * snap_flag member individually. */
+ enum { SCE_SNAP_SEQ = (1 << 7) };
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
+ /* Set default value for the new bisect_threshold parameter in the mirror modifier. */
+ if (!DNA_struct_elem_find(fd->filesdna, "MirrorModifierData", "float", "bisect_threshold")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+ /* This was the previous hard-coded value. */
+ mmd->bisect_threshold = 0.001f;
+ }
+ }
+ }
+ }
+ /* Grease Pencil: Set default value for dilate pixels. */
+ if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "int", "dilate_pixels")) {
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->gpencil_settings) {
+ brush->gpencil_settings->dilate_pixels = 1;
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 2)) {
+ version_switch_node_input_prefix(bmain);
+
+ if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "custom_scale_xyz[3]")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->pose == nullptr) {
+ continue;
+ }
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ copy_v3_fl(pchan->custom_scale_xyz, pchan->custom_scale);
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 4)) {
+ /* Add a properties sidebar to the spreadsheet editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *new_sidebar = do_versions_add_region_if_not_found(
+ regionbase, RGN_TYPE_UI, "sidebar for spreadsheet", RGN_TYPE_FOOTER);
+ if (new_sidebar != nullptr) {
+ new_sidebar->alignment = RGN_ALIGN_RIGHT;
+ new_sidebar->flag |= RGN_FLAG_HIDDEN;
+ }
+ }
+ }
+ }
+ }
+
+ /* Enable spreadsheet filtering in old files without row filters. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+ sspreadsheet->filter_flag |= SPREADSHEET_FILTER_ENABLE;
+ }
+ }
+ }
+ }
+
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_socket_name(ntree, GEO_NODE_BOUNDING_BOX, "Mesh", "Bounding Box");
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ if (!DNA_struct_elem_find(fd->filesdna, "FileAssetSelectParams", "short", "import_type")) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+ if (sfile->asset_params) {
+ sfile->asset_params->import_type = FILE_ASSET_IMPORT_APPEND;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Initialize length-wise scale B-Bone settings. */
+ if (!DNA_struct_elem_find(fd->filesdna, "Bone", "int", "bbone_flag")) {
+ /* Update armature data and pose channels. */
+ LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
+ do_version_bones_bbone_len_scale(&arm->bonebase);
+ }
+
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->pose) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ copy_v3_fl3(pchan->scale_in, pchan->scale_in_x, 1.0f, pchan->scale_in_z);
+ copy_v3_fl3(pchan->scale_out, pchan->scale_out_x, 1.0f, pchan->scale_out_z);
+ }
+ }
+ }
+
+ /* Update action curves and drivers. */
+ LISTBASE_FOREACH (bAction *, act, &bmain->actions) {
+ LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &act->curves) {
+ do_version_bbone_len_scale_fcurve_fix(fcu);
+ }
+ }
+
+ BKE_animdata_main_cb(bmain, do_version_bbone_len_scale_animdata_cb, nullptr);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 5)) {
+ /* Add a dataset sidebar to the spreadsheet editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *spreadsheet_dataset_region = do_versions_add_region_if_not_found(
+ regionbase, RGN_TYPE_CHANNELS, "spreadsheet dataset region", RGN_TYPE_FOOTER);
+
+ if (spreadsheet_dataset_region) {
+ spreadsheet_dataset_region->alignment = RGN_ALIGN_LEFT;
+ spreadsheet_dataset_region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 6)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ /* Disable View Layers filter. */
+ if (space->spacetype == SPACE_OUTLINER) {
+ SpaceOutliner *space_outliner = (SpaceOutliner *)space;
+ space_outliner->filter |= SO_FILTER_NO_VIEW_LAYERS;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 7)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *tool_settings = scene->toolsettings;
+ tool_settings->snap_flag |= SCE_SNAP_SEQ;
+ short snap_mode = tool_settings->snap_mode;
+ short snap_node_mode = tool_settings->snap_node_mode;
+ short snap_uv_mode = tool_settings->snap_uv_mode;
+ tool_settings->snap_mode &= ~((1 << 4) | (1 << 5) | (1 << 6));
+ tool_settings->snap_node_mode &= ~((1 << 5) | (1 << 6));
+ tool_settings->snap_uv_mode &= ~(1 << 4);
+ if (snap_mode & (1 << 4)) {
+ tool_settings->snap_mode |= (1 << 6); /* SCE_SNAP_MODE_INCREMENT */
+ }
+ if (snap_mode & (1 << 5)) {
+ tool_settings->snap_mode |= (1 << 4); /* SCE_SNAP_MODE_EDGE_MIDPOINT */
+ }
+ if (snap_mode & (1 << 6)) {
+ tool_settings->snap_mode |= (1 << 5); /* SCE_SNAP_MODE_EDGE_PERPENDICULAR */
+ }
+ if (snap_node_mode & (1 << 5)) {
+ tool_settings->snap_node_mode |= (1 << 0); /* SCE_SNAP_MODE_NODE_X */
+ }
+ if (snap_node_mode & (1 << 6)) {
+ tool_settings->snap_node_mode |= (1 << 1); /* SCE_SNAP_MODE_NODE_Y */
+ }
+ if (snap_uv_mode & (1 << 4)) {
+ tool_settings->snap_uv_mode |= (1 << 6); /* SCE_SNAP_MODE_INCREMENT */
+ }
+
+ SequencerToolSettings *sequencer_tool_settings = SEQ_tool_settings_ensure(scene);
+ sequencer_tool_settings->snap_mode = SEQ_SNAP_TO_STRIPS | SEQ_SNAP_TO_CURRENT_FRAME |
+ SEQ_SNAP_TO_STRIP_HOLD;
+ sequencer_tool_settings->snap_distance = 15;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 8)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->master_collection != nullptr) {
+ BLI_strncpy(scene->master_collection->id.name + 2,
+ BKE_SCENE_COLLECTION_NAME,
+ sizeof(scene->master_collection->id.name) - 2);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 9)) {
+ /* Fix a bug where reordering FCurves and bActionGroups could cause some corruption. Just
+ * reconstruct all the action groups & ensure that the FCurves of a group are continuously
+ * stored (i.e. not mixed with other groups) to be sure. See T89435. */
+ LISTBASE_FOREACH (bAction *, act, &bmain->actions) {
+ BKE_action_groups_reconstruct(act);
+ }
+
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_SUBDIVIDE_MESH) {
+ strcpy(node->idname, "GeometryNodeMeshSubdivide");
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 10)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *tool_settings = scene->toolsettings;
+ if (tool_settings->snap_uv_mode & (1 << 4)) {
+ tool_settings->snap_uv_mode |= (1 << 6); /* SCE_SNAP_MODE_INCREMENT */
+ tool_settings->snap_uv_mode &= ~(1 << 4);
+ }
+ }
+ LISTBASE_FOREACH (Material *, mat, &bmain->materials) {
+ if (!(mat->lineart.flags & LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS)) {
+ mat->lineart.mat_occlusion = 1;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 13)) {
+ /* Convert Surface Deform to sparse-capable bind structure. */
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "SurfaceDeformModifierData", "int", "num_mesh_verts")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_SurfaceDeform) {
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ if (smd->bind_verts_num && smd->verts) {
+ smd->mesh_verts_num = smd->bind_verts_num;
+
+ for (uint i = 0; i < smd->bind_verts_num; i++) {
+ smd->verts[i].vertex_idx = i;
+ }
+ }
+ }
+ }
+ if (ob->type == OB_GPENCIL) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ if (md->type == eGpencilModifierType_Lineart) {
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+ lmd->flags |= LRT_GPENCIL_USE_CACHE;
+ lmd->chain_smooth_tolerance = 0.2f;
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library")) {
+ LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
+ BKE_asset_library_reference_init_default(&workspace->asset_library_ref);
+ }
+ }
+
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "FileAssetSelectParams", "AssetLibraryReference", "asset_library_ref")) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)space;
+ if (sfile->browse_mode != FILE_BROWSE_MODE_ASSETS) {
+ continue;
+ }
+ BKE_asset_library_reference_init_default(&sfile->asset_params->asset_library_ref);
+ }
+ }
+ }
+ }
+ }
+
+ /* Set default 2D annotation placement. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *ts = scene->toolsettings;
+ ts->gpencil_v2d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 14)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *tool_settings = scene->toolsettings;
+ tool_settings->snap_flag &= ~SCE_SNAP_SEQ;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 15)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ sseq->flag |= SEQ_TIMELINE_SHOW_GRID;
+ }
+ }
+ }
+ }
+ }
+
+ /* Font names were copied directly into ID names, see: T90417. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 16)) {
+ ListBase *lb = which_libbase(bmain, ID_VF);
+ BKE_main_id_repair_duplicate_names_listbase(bmain, lb);
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 17)) {
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "View3DOverlay", "float", "normals_constant_screen_size")) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.normals_constant_screen_size = 7.0f;
+ }
+ }
+ }
+ }
+ }
+
+ /* Fix SplineIK constraint's inconsistency between binding points array and its stored size.
+ */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ /* NOTE: Objects should never have SplineIK constraint, so no need to apply this fix on
+ * their constraints. */
+ if (ob->pose) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ do_version_constraints_spline_ik_joint_bindings(&pchan->constraints);
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 18)) {
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library_ref")) {
+ LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
+ BKE_asset_library_reference_init_default(&workspace->asset_library_ref);
+ }
+ }
+
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "FileAssetSelectParams", "AssetLibraryReference", "asset_library_ref")) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype != SPACE_FILE) {
+ continue;
+ }
+
+ SpaceFile *sfile = (SpaceFile *)space;
+ if (sfile->browse_mode != FILE_BROWSE_MODE_ASSETS) {
+ continue;
+ }
+ BKE_asset_library_reference_init_default(&sfile->asset_params->asset_library_ref);
+ }
+ }
+ }
+ }
+
+ /* Previously, only text ending with `.py` would run, apply this logic
+ * to existing files so text that happens to have the "Register" enabled
+ * doesn't suddenly start running code on startup that was previously ignored. */
+ LISTBASE_FOREACH (Text *, text, &bmain->texts) {
+ if ((text->flags & TXT_ISSCRIPT) && !BLI_path_extension_check(text->id.name + 2, ".py")) {
+ text->flags &= ~TXT_ISSCRIPT;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 19)) {
+ /* Disable Fade Inactive Overlay by default as it is redundant after introducing flash on
+ * mode transfer. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.flag &= ~V3D_OVERLAY_FADE_INACTIVE;
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ SequencerToolSettings *sequencer_tool_settings = SEQ_tool_settings_ensure(scene);
+ sequencer_tool_settings->overlap_mode = SEQ_OVERLAP_SHUFFLE;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 20)) {
+ /* Use new vector Size socket in Cube Mesh Primitive node. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->tonode->type == GEO_NODE_MESH_PRIMITIVE_CUBE) {
+ bNode *node = link->tonode;
+ if (STREQ(link->tosock->identifier, "Size") && link->tosock->type == SOCK_FLOAT) {
+ bNode *link_fromnode = link->fromnode;
+ bNodeSocket *link_fromsock = link->fromsock;
+ bNodeSocket *socket = link->tosock;
+ BLI_assert(socket);
+
+ bNodeSocket *new_socket = do_version_replace_float_size_with_vector(
+ ntree, node, socket);
+ nodeAddLink(ntree, link_fromnode, link_fromsock, node, new_socket);
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_MESH_PRIMITIVE_CUBE) {
+ continue;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (STREQ(socket->identifier, "Size") && (socket->type == SOCK_FLOAT)) {
+ do_version_replace_float_size_with_vector(ntree, node, socket);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 22)) {
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "LineartGpencilModifierData", "bool", "use_crease_on_smooth")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_GPENCIL) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ if (md->type == eGpencilModifierType_Lineart) {
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+ lmd->calculation_flags |= LRT_USE_CREASE_ON_SMOOTH_SURFACES;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 23)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+ if (sfile->asset_params) {
+ sfile->asset_params->base_params.recursion_level = FILE_SELECT_MAX_RECURSIONS;
+ }
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ int seq_show_safe_margins = (sseq->flag & SEQ_PREVIEW_SHOW_SAFE_MARGINS);
+ int seq_show_gpencil = (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL);
+ int seq_show_fcurves = (sseq->flag & SEQ_TIMELINE_SHOW_FCURVES);
+ int seq_show_safe_center = (sseq->flag & SEQ_PREVIEW_SHOW_SAFE_CENTER);
+ int seq_show_metadata = (sseq->flag & SEQ_PREVIEW_SHOW_METADATA);
+ int seq_show_strip_name = (sseq->flag & SEQ_TIMELINE_SHOW_STRIP_NAME);
+ int seq_show_strip_source = (sseq->flag & SEQ_TIMELINE_SHOW_STRIP_SOURCE);
+ int seq_show_strip_duration = (sseq->flag & SEQ_TIMELINE_SHOW_STRIP_DURATION);
+ int seq_show_grid = (sseq->flag & SEQ_TIMELINE_SHOW_GRID);
+ int show_strip_offset = (sseq->draw_flag & SEQ_TIMELINE_SHOW_STRIP_OFFSETS);
+ sseq->preview_overlay.flag = (seq_show_safe_margins | seq_show_gpencil |
+ seq_show_safe_center | seq_show_metadata);
+ sseq->timeline_overlay.flag = (seq_show_fcurves | seq_show_strip_name |
+ seq_show_strip_source | seq_show_strip_duration |
+ seq_show_grid | show_strip_offset);
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 24)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ SequencerToolSettings *sequencer_tool_settings = SEQ_tool_settings_ensure(scene);
+ sequencer_tool_settings->pivot_point = V3D_AROUND_CENTER_MEDIAN;
+
+ if (scene->ed != nullptr) {
+ SEQ_for_each_callback(&scene->ed->seqbase, seq_transform_origin_set, nullptr);
+ }
+ }
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ sseq->preview_overlay.flag |= SEQ_PREVIEW_SHOW_OUTLINE_SELECTED;
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SEQ) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ region->v2d.min[1] = 4.0f;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 25)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ do_version_subsurface_methods(node);
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ enum {
+ R_EXR_TILE_FILE = (1 << 10),
+ R_FULL_SAMPLE = (1 << 15),
+ };
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ scene->r.scemode &= ~(R_EXR_TILE_FILE | R_FULL_SAMPLE);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 26)) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ version_geometry_nodes_add_attribute_input_settings((NodesModifierData *)md);
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_FILE: {
+ SpaceFile *sfile = (SpaceFile *)sl;
+ if (sfile->params) {
+ sfile->params->flag &= ~(FILE_PARAMS_FLAG_UNUSED_1 | FILE_PARAMS_FLAG_UNUSED_2 |
+ FILE_PARAMS_FLAG_UNUSED_3 | FILE_PATH_TOKENS_ALLOW);
+ }
+
+ /* New default import type: Append with reuse. */
+ if (sfile->asset_params) {
+ sfile->asset_params->import_type = FILE_ASSET_IMPORT_APPEND_REUSE;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 29)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_SEQ: {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ region->v2d.max[1] = MAXSEQ;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 31)) {
+ /* Swap header with the tool header so the regular header is always on the edge. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *region_tool = nullptr, *region_head = nullptr;
+ int region_tool_index = -1, region_head_index = -1, i;
+ LISTBASE_FOREACH_INDEX (ARegion *, region, regionbase, i) {
+ if (region->regiontype == RGN_TYPE_TOOL_HEADER) {
+ region_tool = region;
+ region_tool_index = i;
+ }
+ else if (region->regiontype == RGN_TYPE_HEADER) {
+ region_head = region;
+ region_head_index = i;
+ }
+ }
+ if ((region_tool && region_head) && (region_head_index > region_tool_index)) {
+ BLI_listbase_swaplinks(regionbase, region_tool, region_head);
+ }
+ }
+ }
+ }
+
+ /* Set strip color tags to SEQUENCE_COLOR_NONE. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->ed != nullptr) {
+ SEQ_for_each_callback(&scene->ed->seqbase, do_versions_sequencer_color_tags, nullptr);
+ }
+ }
+
+ /* Show sequencer color tags by default. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ sseq->timeline_overlay.flag |= SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG;
+ }
+ }
+ }
+ }
+
+ /* Set defaults for new color balance modifier parameters. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->ed != nullptr) {
+ SEQ_for_each_callback(
+ &scene->ed->seqbase, do_versions_sequencer_color_balance_sop, nullptr);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 33)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ enum { SEQ_DRAW_SEQUENCE = 0 };
+ if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
+ sseq->mainb = SEQ_DRAW_IMG_IMBUF;
+ }
+ break;
+ }
+ case SPACE_TEXT: {
+ SpaceText *st = (SpaceText *)sl;
+ st->flags &= ~ST_FLAG_UNUSED_4;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 36)) {
+ /* Update the `idnames` for renamed geometry and function nodes. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ version_node_id(ntree, FN_NODE_COMPARE, "FunctionNodeCompareFloats");
+ version_node_id(ntree, GEO_NODE_CAPTURE_ATTRIBUTE, "GeometryNodeCaptureAttribute");
+ version_node_id(ntree, GEO_NODE_MESH_BOOLEAN, "GeometryNodeMeshBoolean");
+ version_node_id(ntree, GEO_NODE_FILL_CURVE, "GeometryNodeFillCurve");
+ version_node_id(ntree, GEO_NODE_FILLET_CURVE, "GeometryNodeFilletCurve");
+ version_node_id(ntree, GEO_NODE_REVERSE_CURVE, "GeometryNodeReverseCurve");
+ version_node_id(ntree, GEO_NODE_SAMPLE_CURVE, "GeometryNodeSampleCurve");
+ version_node_id(ntree, GEO_NODE_RESAMPLE_CURVE, "GeometryNodeResampleCurve");
+ version_node_id(ntree, GEO_NODE_SUBDIVIDE_CURVE, "GeometryNodeSubdivideCurve");
+ version_node_id(ntree, GEO_NODE_TRIM_CURVE, "GeometryNodeTrimCurve");
+ version_node_id(ntree, GEO_NODE_REPLACE_MATERIAL, "GeometryNodeReplaceMaterial");
+ version_node_id(ntree, GEO_NODE_SUBDIVIDE_MESH, "GeometryNodeSubdivideMesh");
+ version_node_id(ntree, GEO_NODE_SET_MATERIAL, "GeometryNodeSetMaterial");
+ version_node_id(ntree, GEO_NODE_SPLIT_EDGES, "GeometryNodeSplitEdges");
+ }
+
+ /* Update bone roll after a fix to vec_roll_to_mat3_normalized. */
+ LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
+ do_version_bones_roll(&arm->bonebase);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 37)) {
+ /* Node Editor: toggle overlays on. */
+ if (!DNA_struct_find(fd->filesdna, "SpaceNodeOverlay")) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)space;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_OVERLAYS;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_WIRE_COLORS;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 38)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)space;
+ FileAssetSelectParams *asset_params = sfile->asset_params;
+ if (asset_params) {
+ asset_params->base_params.filter_id = FILTER_ID_ALL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 39)) {
+ LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
+ wm->xr.session_settings.base_scale = 1.0f;
+ wm->xr.session_settings.draw_flags |= (V3D_OFSDRAW_SHOW_SELECTION |
+ V3D_OFSDRAW_XR_SHOW_CONTROLLERS |
+ V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 40)) {
+ /* Update the `idnames` for renamed geometry and function nodes. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ version_node_id(ntree, FN_NODE_SLICE_STRING, "FunctionNodeSliceString");
+ version_geometry_nodes_set_position_node_offset(ntree);
+ }
+
+ /* Add storage to viewer node. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_VIEWER) {
+ if (node->storage == nullptr) {
+ NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(
+ sizeof(NodeGeometryViewer), __func__);
+ data->data_type = CD_PROP_FLOAT;
+ node->storage = data;
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(
+ ntree, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, "Geometry", "Mesh");
+ version_node_input_socket_name(ntree, GEO_NODE_POINTS_TO_VOLUME, "Geometry", "Points");
+ version_node_output_socket_name(ntree, GEO_NODE_POINTS_TO_VOLUME, "Geometry", "Volume");
+ version_node_socket_name(ntree, GEO_NODE_SUBDIVISION_SURFACE, "Geometry", "Mesh");
+ version_node_socket_name(ntree, GEO_NODE_RESAMPLE_CURVE, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SUBDIVIDE_CURVE, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SET_CURVE_RADIUS, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SET_CURVE_TILT, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SET_CURVE_HANDLES, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_TRANSLATE_INSTANCES, "Geometry", "Instances");
+ version_node_socket_name(ntree, GEO_NODE_ROTATE_INSTANCES, "Geometry", "Instances");
+ version_node_socket_name(ntree, GEO_NODE_SCALE_INSTANCES, "Geometry", "Instances");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry", "Mesh");
+ version_node_input_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry 1", "Mesh 1");
+ version_node_input_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry 2", "Mesh 2");
+ version_node_socket_name(ntree, GEO_NODE_SUBDIVIDE_MESH, "Geometry", "Mesh");
+ version_node_socket_name(ntree, GEO_NODE_TRIANGULATE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_CONE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_CUBE, "Geometry", "Mesh");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_GRID, "Geometry", "Mesh");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_LINE, "Geometry", "Mesh");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "Geometry", "Mesh");
+ version_node_socket_name(ntree, GEO_NODE_SET_POINT_RADIUS, "Geometry", "Points");
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 42)) {
+ /* Use consistent socket identifiers for the math node.
+ * The code to make unique identifiers from the names was inconsistent. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type != NTREE_CUSTOM) {
+ version_node_tree_socket_id_delim(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SEQ) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ region->v2d.min[1] = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Change minimum zoom to 0.05f in the node editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_NODE) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ if (region->v2d.minzoom > 0.05f) {
+ region->v2d.minzoom = 0.05f;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ Editing *ed = SEQ_editing_get(scene);
+ /* Make sure range of meta strips is correct.
+ * It was possible to save .blend file with incorrect state of meta strip
+ * range. The root cause is expected to be fixed, but need to ensure files
+ * with invalid meta strip range are corrected. */
+ if (ed != nullptr) {
+ SEQ_for_each_callback(&ed->seqbase, version_fix_seq_meta_range, scene);
+ }
+ }
+ }
+
+ /* Special case to handle older in-development 3.1 files, before change from 3.0 branch gets
+ * merged in master. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 42) ||
+ (bmain->versionfile == 301 && !MAIN_VERSION_ATLEAST(bmain, 301, 3))) {
+ /* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers,
+ * constraints and NLA tracks). */
+ ID *id_iter;
+ FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) {
+ version_liboverride_rnacollections_insertion_animdata(id_iter);
+ if (GS(id_iter->name) == ID_OB) {
+ version_liboverride_rnacollections_insertion_object((Object *)id_iter);
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 4)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ version_node_id(ntree, GEO_NODE_CURVE_SPLINE_PARAMETER, "GeometryNodeSplineParameter");
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_CURVE_SPLINE_PARAMETER) {
+ version_node_add_socket_if_not_exist(
+ ntree, node, SOCK_OUT, SOCK_INT, PROP_NONE, "Index", "Index");
+ }
+
+ /* Convert float compare into a more general compare node. */
+ if (node->type == FN_NODE_COMPARE) {
+ if (node->storage == nullptr) {
+ NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN(
+ sizeof(NodeFunctionCompare), __func__);
+ data->data_type = SOCK_FLOAT;
+ data->operation = node->custom1;
+ strcpy(node->idname, "FunctionNodeCompare");
+ node->storage = data;
+ }
+ }
+ }
+ }
+
+ /* Add a toggle for the breadcrumbs overlay in the node editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)space;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_PATH;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_REALIZE_INSTANCES) {
+ continue;
+ }
+ node->custom1 |= GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 6)) {
+ /* Add node storage for map range node. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_MAP_RANGE) {
+ if (node->storage == nullptr) {
+ NodeMapRange *data = MEM_cnew<NodeMapRange>(__func__);
+ data->clamp = node->custom1;
+ data->data_type = CD_PROP_FLOAT;
+ data->interpolation_type = node->custom2;
+ node->storage = data;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ /* Update spreadsheet data set region type. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_CHANNELS) {
+ region->regiontype = RGN_TYPE_TOOLS;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Initialize the bone wireframe opacity setting. */
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "bone_wire_alpha")) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.bone_wire_alpha = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ /* Rename sockets on multiple nodes */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_output_socket_name(
+ ntree, GEO_NODE_STRING_TO_CURVES, "Curves", "Curve Instances");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_INPUT_MESH_EDGE_ANGLE, "Angle", "Unsigned Angle");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_INPUT_MESH_ISLAND, "Index", "Island Index");
+ version_node_input_socket_name(
+ ntree, GEO_NODE_TRANSFER_ATTRIBUTE_DEPRECATED, "Target", "Source");
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 7) ||
+ (bmain->versionfile == 302 && !MAIN_VERSION_ATLEAST(bmain, 302, 4))) {
+ /* Duplicate value for two flags that mistakenly had the same numeric value. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_WeightVGProximity) {
+ WeightVGProximityModifierData *wpmd = (WeightVGProximityModifierData *)md;
+ if (wpmd->proximity_flags & MOD_WVG_PROXIMITY_INVERT_VGROUP_MASK) {
+ wpmd->proximity_flags |= MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 2)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->ed != nullptr) {
+ SEQ_for_each_callback(&scene->ed->seqbase, seq_transform_filter_set, nullptr);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 6)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *ts = scene->toolsettings;
+ if (ts->uv_relax_method == 0) {
+ ts->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN;
+ }
+ }
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *tool_settings = scene->toolsettings;
+ tool_settings->snap_flag_seq = tool_settings->snap_flag &
+ ~(short(SCE_SNAP) | short(SCE_SNAP_SEQ));
+ if (tool_settings->snap_flag & SCE_SNAP_SEQ) {
+ tool_settings->snap_flag_seq |= SCE_SNAP;
+ tool_settings->snap_flag &= ~SCE_SNAP_SEQ;
+ }
+
+ tool_settings->snap_flag_node = tool_settings->snap_flag;
+ tool_settings->snap_uv_flag |= tool_settings->snap_flag & SCE_SNAP;
+ }
+
+ /* Alter NURBS knot mode flags to fit new modes. */
+ LISTBASE_FOREACH (Curve *, curve, &bmain->curves) {
+ LISTBASE_FOREACH (Nurb *, nurb, &curve->nurb) {
+ /* Previously other flags were ignored if CU_NURB_CYCLIC is set. */
+ if (nurb->flagu & CU_NURB_CYCLIC) {
+ nurb->flagu = CU_NURB_CYCLIC;
+ }
+ /* CU_NURB_BEZIER and CU_NURB_ENDPOINT were ignored if combined. */
+ else if (nurb->flagu & CU_NURB_BEZIER && nurb->flagu & CU_NURB_ENDPOINT) {
+ nurb->flagu &= ~(CU_NURB_BEZIER | CU_NURB_ENDPOINT);
+ BKE_nurb_knot_calc_u(nurb);
+ }
+ /* Bezier NURBS of order 3 were clamped to first control point. */
+ else if (nurb->orderu == 3 && (nurb->flagu & CU_NURB_BEZIER)) {
+ nurb->flagu |= CU_NURB_ENDPOINT;
+ }
+
+ /* Previously other flags were ignored if CU_NURB_CYCLIC is set. */
+ if (nurb->flagv & CU_NURB_CYCLIC) {
+ nurb->flagv = CU_NURB_CYCLIC;
+ }
+ /* CU_NURB_BEZIER and CU_NURB_ENDPOINT were ignored if used together. */
+ else if (nurb->flagv & CU_NURB_BEZIER && nurb->flagv & CU_NURB_ENDPOINT) {
+ nurb->flagv &= ~(CU_NURB_BEZIER | CU_NURB_ENDPOINT);
+ BKE_nurb_knot_calc_v(nurb);
+ }
+ /* Bezier NURBS of order 3 were clamped to first control point. */
+ else if (nurb->orderv == 3 && (nurb->flagv & CU_NURB_BEZIER)) {
+ nurb->flagv |= CU_NURB_ENDPOINT;
+ }
+ }
+ }
+
+ /* Change grease pencil smooth iterations to match old results with new algorithm. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ if (md->type == eGpencilModifierType_Smooth) {
+ SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
+ if (gpmd->step == 1 && gpmd->factor <= 0.5f) {
+ gpmd->factor *= 2.0f;
+ }
+ else {
+ gpmd->step = 1 + int(gpmd->factor * max_ff(0.0f,
+ min_ff(5.1f * sqrtf(gpmd->step) - 3.0f,
+ gpmd->step + 2.0f)));
+ gpmd->factor = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ /* Rebuild active/render color attribute references. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 6)) {
+ LISTBASE_FOREACH (Brush *, br, &bmain->brushes) {
+ /* Buggy code in wm_toolsystem broke smear in old files,
+ * reset to defaults. */
+ if (br->sculpt_tool == SCULPT_TOOL_SMEAR) {
+ br->alpha = 1.0f;
+ br->spacing = 5;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->curve_preset = BRUSH_CURVE_SPHERE;
+ }
+ }
+
+ LISTBASE_FOREACH (Mesh *, me, &bmain->meshes) {
+ for (int step = 0; step < 2; step++) {
+ CustomDataLayer *actlayer = nullptr;
+
+ int vact1, vact2;
+
+ if (step) {
+ vact1 = CustomData_get_render_layer_index(&me->vdata, CD_PROP_COLOR);
+ vact2 = CustomData_get_render_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
+ }
+ else {
+ vact1 = CustomData_get_active_layer_index(&me->vdata, CD_PROP_COLOR);
+ vact2 = CustomData_get_active_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
+ }
+
+ if (vact1 != -1) {
+ actlayer = me->vdata.layers + vact1;
+ }
+ else if (vact2 != -1) {
+ actlayer = me->ldata.layers + vact2;
+ }
+
+ if (actlayer) {
+ if (step) {
+ BKE_id_attributes_render_color_set(&me->id, actlayer);
+ }
+ else {
+ BKE_id_attributes_active_color_set(&me->id, actlayer);
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 7)) {
+ /* Generate 'system' liboverrides IDs.
+ * NOTE: This is a fairly rough process, based on very basic heuristics. Should be enough for a
+ * do_version code though, this is a new optional feature, not a critical conversion. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || ID_IS_LINKED(id)) {
+ /* Ignore non-real liboverrides, and linked ones. */
+ continue;
+ }
+ if (GS(id->name) == ID_OB) {
+ /* Never 'lock' an object into a system override for now. */
+ continue;
+ }
+ if (BKE_lib_override_library_is_user_edited(id)) {
+ /* Do not 'lock' an ID already edited by the user. */
+ continue;
+ }
+ id->override_library->flag |= IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ }
+ FOREACH_MAIN_ID_END;
+
+ /* Initialize brush curves sculpt settings. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->ob_mode != OB_MODE_SCULPT_CURVES) {
+ continue;
+ }
+ if (brush->curves_sculpt_settings != nullptr) {
+ continue;
+ }
+ brush->curves_sculpt_settings = MEM_cnew<BrushCurvesSculptSettings>(__func__);
+ brush->curves_sculpt_settings->add_amount = 1;
+ }
+
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
+ space_outliner->filter &= ~SO_FILTER_CLEARED_1;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 9)) {
+ /* Sequencer channels region. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype != SPACE_SEQ) {
+ continue;
+ }
+ if (ELEM(((SpaceSeq *)sl)->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
+ continue;
+ }
+
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *region = BKE_region_find_in_listbase_by_type(regionbase, RGN_TYPE_CHANNELS);
+ if (!region) {
+ /* Find sequencer tools region. */
+ ARegion *tools_region = BKE_region_find_in_listbase_by_type(regionbase,
+ RGN_TYPE_TOOLS);
+ region = do_versions_add_region(RGN_TYPE_CHANNELS, "channels region");
+ BLI_insertlinkafter(regionbase, tools_region, region);
+ region->alignment = RGN_ALIGN_LEFT;
+ region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL;
+ }
+
+ ARegion *timeline_region = BKE_region_find_in_listbase_by_type(regionbase,
+ RGN_TYPE_WINDOW);
+ if (timeline_region != nullptr) {
+ timeline_region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL;
+ }
+ }
+ }
+ }
+
+ /* Initialize channels. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ Editing *ed = SEQ_editing_get(scene);
+ if (ed == nullptr) {
+ continue;
+ }
+ SEQ_channels_ensure(&ed->channels);
+ SEQ_for_each_callback(&scene->ed->seqbase, seq_meta_channels_ensure, nullptr);
+
+ ed->displayed_channels = &ed->channels;
+
+ ListBase *previous_channels = &ed->channels;
+ LISTBASE_FOREACH (MetaStack *, ms, &ed->metastack) {
+ ms->old_channels = previous_channels;
+ previous_channels = &ms->parseq->channels;
+ /* If `MetaStack` exists, active channels must point to last link. */
+ ed->displayed_channels = &ms->parseq->channels;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 10)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype != SPACE_FILE) {
+ continue;
+ }
+ SpaceFile *sfile = (SpaceFile *)sl;
+ if (sfile->browse_mode != FILE_BROWSE_MODE_ASSETS) {
+ continue;
+ }
+ sfile->asset_params->base_params.filter_id |= FILTER_ID_GR;
+ }
+ }
+ }
+
+ /* While vertex-colors were experimental the smear tool became corrupt due
+ * to bugs in the wm_toolsystem API (auto-creation of sculpt brushes
+ * was broken). Go through and reset all smear brushes. */
+ LISTBASE_FOREACH (Brush *, br, &bmain->brushes) {
+ if (br->sculpt_tool == SCULPT_TOOL_SMEAR) {
+ br->alpha = 1.0f;
+ br->spacing = 5;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->curve_preset = BRUSH_CURVE_SPHERE;
+ }
+ }
+
+ /* Rebuild active/render color attribute references. */
+ LISTBASE_FOREACH (Mesh *, me, &bmain->meshes) {
+ for (int step = 0; step < 2; step++) {
+ CustomDataLayer *actlayer = nullptr;
+
+ int vact1, vact2;
+
+ if (step) {
+ vact1 = CustomData_get_render_layer_index(&me->vdata, CD_PROP_COLOR);
+ vact2 = CustomData_get_render_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
+ }
+ else {
+ vact1 = CustomData_get_active_layer_index(&me->vdata, CD_PROP_COLOR);
+ vact2 = CustomData_get_active_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
+ }
+
+ if (vact1 != -1) {
+ actlayer = me->vdata.layers + vact1;
+ }
+ else if (vact2 != -1) {
+ actlayer = me->ldata.layers + vact2;
+ }
+
+ if (actlayer) {
+ if (step) {
+ BKE_id_attributes_render_color_set(&me->id, actlayer);
+ }
+ else {
+ BKE_id_attributes_active_color_set(&me->id, actlayer);
+ }
+ }
+ }
+ }
+
+ /* Update data transfer modifiers */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_DataTransfer) {
+ DataTransferModifierData *dtmd = (DataTransferModifierData *)md;
+
+ for (int i = 0; i < DT_MULTILAYER_INDEX_MAX; i++) {
+ if (dtmd->layers_select_src[i] == 0) {
+ dtmd->layers_select_src[i] = DT_LAYERS_ALL_SRC;
+ }
+
+ if (dtmd->layers_select_dst[i] == 0) {
+ dtmd->layers_select_dst[i] = DT_LAYERS_NAME_DST;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 12)) {
+ /* UV/Image show background grid option. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)space;
+ sima->overlay.flag |= SI_OVERLAY_SHOW_GRID_BACKGROUND;
+ }
+ }
+ }
+ }
+
+ /* Add node storage for the merge by distance node. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_MERGE_BY_DISTANCE) {
+ if (node->storage == nullptr) {
+ NodeGeometryMergeByDistance *data = MEM_cnew<NodeGeometryMergeByDistance>(__func__);
+ data->mode = GEO_NODE_MERGE_BY_DISTANCE_MODE_ALL;
+ node->storage = data;
+ }
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(
+ ntree, GEO_NODE_SUBDIVISION_SURFACE, "Crease", "Edge Crease");
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 13)) {
+ /* Enable named attributes overlay in node editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)space;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_NAMED_ATTRIBUTES;
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ BrushCurvesSculptSettings *settings = brush->curves_sculpt_settings;
+ if (settings == nullptr) {
+ continue;
+ }
+ if (settings->curve_length == 0.0f) {
+ settings->curve_length = 0.3f;
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "Sculpt", "float", "automasking_cavity_factor")) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->toolsettings && scene->toolsettings->sculpt) {
+ scene->toolsettings->sculpt->automasking_cavity_factor = 0.5f;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 14)) {
+ /* Compensate for previously wrong squared distance. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ scene->r.bake.max_ray_distance = sasqrt(scene->r.bake.max_ray_distance);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 1)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ versioning_replace_legacy_combined_and_separate_color_nodes(ntree);
+ }
+ FOREACH_NODETREE_END;
+
+ /* Initialize brush curves sculpt settings. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->ob_mode != OB_MODE_SCULPT_CURVES) {
+ continue;
+ }
+ if (brush->curves_sculpt_settings->points_per_curve == 0) {
+ brush->curves_sculpt_settings->points_per_curve = 8;
+ }
+ }
+
+ /* UDIM Packing. */
+ if (!DNA_struct_elem_find(fd->filesdna, "ImagePackedFile", "int", "tile_number")) {
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ int view;
+ LISTBASE_FOREACH_INDEX (ImagePackedFile *, imapf, &ima->packedfiles, view) {
+ imapf->view = view;
+ imapf->tile_number = 1001;
+ }
+ }
+ }
+
+ /* Merge still offsets into start/end offsets. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ Editing *ed = SEQ_editing_get(scene);
+ if (ed != nullptr) {
+ SEQ_for_each_callback(&ed->seqbase, version_merge_still_offsets, nullptr);
+ }
+ }
+
+ /* Use the curves type enum for the set spline type node, instead of a special one. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_CURVE_SPLINE_TYPE) {
+ NodeGeometryCurveSplineType *storage = (NodeGeometryCurveSplineType *)node->storage;
+ switch (storage->spline_type) {
+ case 0: /* GEO_NODE_SPLINE_TYPE_BEZIER */
+ storage->spline_type = CURVE_TYPE_BEZIER;
+ break;
+ case 1: /* GEO_NODE_SPLINE_TYPE_NURBS */
+ storage->spline_type = CURVE_TYPE_NURBS;
+ break;
+ case 2: /* GEO_NODE_SPLINE_TYPE_POLY */
+ storage->spline_type = CURVE_TYPE_POLY;
+ break;
+ }
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (GpencilModifierData *, gpd, &ob->greasepencil_modifiers) {
+ if (gpd->type == eGpencilModifierType_Lineart) {
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)gpd;
+ lmd->shadow_camera_near = 0.1f;
+ lmd->shadow_camera_far = 200.0f;
+ lmd->shadow_camera_size = 200.0f;
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 2)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_CLIP) {
+ ((SpaceClip *)sl)->mask_info.blend_factor = 1.0;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 3)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_CLIP) {
+ ((SpaceClip *)sl)->mask_info.draw_flag |= MASK_DRAWFLAG_SPLINE;
+ }
+ else if (sl->spacetype == SPACE_IMAGE) {
+ ((SpaceImage *)sl)->mask_info.draw_flag |= MASK_DRAWFLAG_SPLINE;
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *tool_settings = scene->toolsettings;
+ /* Zero isn't a valid value, use for versioning. */
+ if (tool_settings->snap_face_nearest_steps == 0) {
+ /* Minimum of snap steps for face nearest is 1. */
+ tool_settings->snap_face_nearest_steps = 1;
+ /* Set snap to edited and non-edited as default. */
+ tool_settings->snap_flag |= SCE_SNAP_TO_INCLUDE_EDITED | SCE_SNAP_TO_INCLUDE_NONEDITED;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 4)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == CMP_NODE_OUTPUT_FILE) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ if (sock->storage) {
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage;
+ version_fix_image_format_copy(bmain, &sockdata->format);
+ }
+ }
+
+ if (node->storage) {
+ NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage;
+ version_fix_image_format_copy(bmain, &nimf->format);
+ }
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ version_fix_image_format_copy(bmain, &scene->r.im_format);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 5)) {
+ /* Fix for T98925 - remove channels region, that was initialized in incorrect editor types. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (ELEM(sl->spacetype, SPACE_ACTION, SPACE_CLIP, SPACE_GRAPH, SPACE_NLA, SPACE_SEQ)) {
+ continue;
+ }
+
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *channels_region = BKE_region_find_in_listbase_by_type(regionbase,
+ RGN_TYPE_CHANNELS);
+ if (channels_region) {
+ BLI_freelinkN(regionbase, channels_region);
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 6)) {
+ /* Initialize brush curves sculpt settings. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->ob_mode != OB_MODE_SCULPT_CURVES) {
+ continue;
+ }
+ brush->curves_sculpt_settings->density_add_attempts = 100;
+ }
+
+ /* Disable 'show_bounds' option of curve objects. Option was set as there was no object mode
+ * outline implementation. See T95933. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_CURVES) {
+ ob->dtx &= ~OB_DRAWBOUNDOX;
+ }
+ }
+
+ BKE_main_namemap_validate_and_fix(bmain);
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 304, 1)) {
+ /* Image generation information transferred to tiles. */
+ if (!DNA_struct_elem_find(fd->filesdna, "ImageTile", "int", "gen_x")) {
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ tile->gen_x = ima->gen_x;
+ tile->gen_y = ima->gen_y;
+ tile->gen_type = ima->gen_type;
+ tile->gen_flag = ima->gen_flag;
+ tile->gen_depth = ima->gen_depth;
+ copy_v4_v4(tile->gen_color, ima->gen_color);
+ }
+ }
+ }
+
+ /* Convert mix rgb node to new mix node and add storage. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ versioning_replace_legacy_mix_rgb_node(ntree);
+ }
+ FOREACH_NODETREE_END;
+
+ /* Face sets no longer store whether the corresponding face is hidden. */
+ LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
+ int *face_sets = (int *)CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
+ if (face_sets) {
+ for (int i = 0; i < mesh->totpoly; i++) {
+ face_sets[i] = abs(face_sets[i]);
+ }
+ }
+ }
+
+ /* Custom grids in UV Editor have separate X and Y divisions. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_IMAGE: {
+ SpaceImage *sima = (SpaceImage *)sl;
+ sima->custom_grid_subdiv[0] = 10;
+ sima->custom_grid_subdiv[1] = 10;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 304, 2)) {
+ /* Initialize brush curves sculpt settings. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ brush->automasking_cavity_factor = 0.5f;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 304, 3)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->flag2 |= V3D_SHOW_VIEWER;
+ v3d->overlay.flag |= V3D_OVERLAY_VIEWER_ATTRIBUTE;
+ v3d->overlay.viewer_attribute_opacity = 1.0f;
+ }
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+ if (sima->flag & SI_FLAG_UNUSED_18) { /* Was #SI_CUSTOM_GRID. */
+ sima->grid_shape_source = SI_GRID_SHAPE_FIXED;
+ sima->flag &= ~SI_FLAG_UNUSED_18;
+ }
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ version_node_id(ntree, GEO_NODE_OFFSET_POINT_IN_CURVE, "GeometryNodeOffsetPointInCurve");
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 304, 4)) {
+ /* Update brush sculpt settings. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ brush->automasking_cavity_factor = 1.0f;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 304, 5)) {
+ /* Fix for T101622 - update flags of sequence editor regions that were not initialized
+ * properly. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ if (sl->spacetype == SPACE_SEQ) {
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_TOOLS) {
+ region->v2d.flag &= ~V2D_VIEWSYNC_AREA_VERTICAL;
+ }
+ if (region->regiontype == RGN_TYPE_CHANNELS) {
+ region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+ }
+}