diff --git a/source/blender/blenkernel/intern/blendfile_link_append.cc b/source/blender/blenkernel/intern/blendfile_link_append.cc index 33025afb757..f9b9b09face 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.cc +++ b/source/blender/blenkernel/intern/blendfile_link_append.cc @@ -1495,6 +1495,7 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re if ((lapp_context->params->flag & FILE_LINK) != 0) { blendfile_link_append_proxies_convert(lapp_context->params->bmain, reports); + BKE_main_mesh_legacy_convert_auto_smooth(*lapp_context->params->bmain); } BKE_main_namemap_clear(lapp_context->params->bmain); diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 596745e6359..e66fee30fc3 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -35,6 +35,7 @@ #include "BKE_customdata.hh" #include "BKE_global.h" #include "BKE_idprop.hh" +#include "BKE_lib_id.hh" #include "BKE_main.hh" #include "BKE_mesh.hh" #include "BKE_mesh_legacy_convert.hh" @@ -2235,17 +2236,105 @@ static bNodeTree *add_auto_smooth_node_tree(Main &bmain) nodeSetSelected(node, false); } + BKE_ntree_update_main_tree(&bmain, group, nullptr); + return group; } -static ModifierData *create_auto_smooth_modifier(Object &object, - const FunctionRef get_node_group, - const float angle) +static VectorSet build_socket_indices(const Span nodes) +{ + VectorSet result; + for (const bNode *node : nodes) { + LISTBASE_FOREACH (const bNodeSocket *, socket, &node->inputs) { + result.add_new(socket); + } + LISTBASE_FOREACH (const bNodeSocket *, socket, &node->outputs) { + result.add_new(socket); + } + } + return result; +} + +/* Checks if the node group is the same as the one generated by #create_auto_smooth_modifier. */ +static bool is_auto_smooth_node_tree(const bNodeTree &group) +{ + if (group.type != NTREE_GEOMETRY) { + return false; + } + const Span nodes = group.all_nodes(); + if (nodes.size() != 10) { + return false; + } + if (!group.geometry_node_asset_traits) { + return false; + } + if (group.geometry_node_asset_traits->flag != GEO_NODE_ASSET_MODIFIER) { + return false; + } + const std::array idnames({"NodeGroupOutput", + "NodeGroupInput", + "NodeGroupInput", + "GeometryNodeSetShadeSmooth", + "GeometryNodeSetShadeSmooth", + "GeometryNodeInputMeshEdgeAngle", + "GeometryNodeInputEdgeSmooth", + "GeometryNodeInputShadeSmooth", + "FunctionNodeBooleanMath", + "FunctionNodeCompare"}); + for (const int i : nodes.index_range()) { + if (nodes[i]->idname != idnames[i]) { + return false; + } + } + if (nodes[3]->custom1 != int16_t(bke::AttrDomain::Edge)) { + return false; + } + if (static_cast(nodes[4]->inputs.last) + ->default_value_typed() + ->value != true) + { + return false; + } + if (nodes[4]->custom1 != int16_t(bke::AttrDomain::Face)) { + return false; + } + if (nodes[8]->custom1 != NODE_BOOLEAN_MATH_AND) { + return false; + } + if (static_cast(nodes[9]->storage)->operation != NODE_COMPARE_LESS_EQUAL) + { + return false; + } + if (BLI_listbase_count(&group.links) != 9) { + return false; + } + + const std::array link_from_socket_indices({16, 15, 3, 36, 19, 5, 18, 11, 22}); + const std::array link_to_socket_indices({23, 0, 24, 20, 21, 8, 9, 12, 10}); + const VectorSet socket_indices = build_socket_indices(nodes); + int i; + LISTBASE_FOREACH_INDEX (const bNodeLink *, link, &group.links, i) { + if (socket_indices.index_of(link->fromsock) != link_from_socket_indices[i]) { + return false; + } + if (socket_indices.index_of(link->tosock) != link_to_socket_indices[i]) { + return false; + } + } + + return true; +} + +static ModifierData *create_auto_smooth_modifier( + Object &object, + const FunctionRef get_node_group, + const float angle) { auto *md = reinterpret_cast(BKE_modifier_new(eModifierType_Nodes)); STRNCPY(md->modifier.name, DATA_("Auto Smooth")); BKE_modifier_unique_name(&object.modifiers, &md->modifier); - md->node_group = get_node_group(); + md->node_group = get_node_group(object.id.lib); + id_us_plus(&md->node_group->id); md->settings.properties = idprop::create_group("Nodes Modifier Settings").release(); IDProperty *angle_prop = idprop::create("Socket_1", angle).release(); @@ -2265,14 +2354,43 @@ static ModifierData *create_auto_smooth_modifier(Object &object, void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain) { + using namespace blender; using namespace blender::bke; - /* Add the node group lazily and share it among all objects in the main database. */ - bNodeTree *node_group = nullptr; - const auto add_node_group = [&]() { - node_group = add_auto_smooth_node_tree(bmain); - BKE_ntree_update_main_tree(&bmain, node_group, nullptr); - return node_group; + /* Add the node group lazily and share it among all objects in the same library. */ + Map group_by_library; + const auto add_node_group = [&](Library *library) { + if (bNodeTree **group = group_by_library.lookup_ptr(library)) { + /* Node tree has already been found/created for this versioning call. */ + return *group; + } + /* Try to find an existing group added by previous versioning to avoid adding duplicates. */ + LISTBASE_FOREACH (bNodeTree *, existing_group, &bmain.nodetrees) { + if (existing_group->id.lib != library) { + continue; + } + if (is_auto_smooth_node_tree(*existing_group)) { + group_by_library.add_new(library, existing_group); + return existing_group; + } + } + bNodeTree *new_group = add_auto_smooth_node_tree(bmain); + /* Remove the default user. The count is tracked manually when assigning to modifiers. */ + id_us_min(&new_group->id); + + if (new_group->id.lib != library) { + /* Move the node group to the requested library so that library data-blocks don't point to + * local data-blocks. This requires making sure the name is unique in that library and + * changing the name maps to be consistent with the new state. */ + new_group->id.lib = library; + BKE_id_new_name_validate(&bmain, &bmain.nodetrees, &new_group->id, nullptr, false); + if (library) { + new_group->id.tag |= LIB_TAG_INDIRECT; + } + } + + group_by_library.add_new(library, new_group); + return new_group; }; LISTBASE_FOREACH (Object *, object, &bmain.objects) { @@ -2284,7 +2402,6 @@ void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain) if (!(mesh->flag & ME_AUTOSMOOTH_LEGACY)) { continue; } - mesh->flag &= ~ME_AUTOSMOOTH_LEGACY; /* Auto-smooth disabled sharp edge tagging when the evaluated mesh had custom normals. * When the original mesh has custom normals, that's a good sign the evaluated mesh will @@ -2333,6 +2450,10 @@ void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain) BLI_addtail(&object->modifiers, new_md); } } + + LISTBASE_FOREACH (Mesh *, mesh, &bmain.meshes) { + mesh->flag &= ~ME_AUTOSMOOTH_LEGACY; + } } namespace blender::bke { diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc index 1e428e3c975..c86df3ba23b 100644 --- a/source/blender/blenloader/intern/versioning_common.cc +++ b/source/blender/blenloader/intern/versioning_common.cc @@ -532,7 +532,10 @@ void do_versions_after_setup(Main *new_bmain, BlendFileReadReport *reports) BKE_lib_override_library_main_hierarchy_root_ensure(new_bmain); } - if (!blendfile_or_libraries_versions_atleast(new_bmain, 401, 2)) { + if (!blendfile_or_libraries_versions_atleast(new_bmain, 402, 22)) { + /* Initial auto smooth versioning started at (401, 2), but a bug caused the legacy flag to not + * be cleared, so it is re-run in a later version when the bug is fixed and the versioning has + * been made idempotent. */ BKE_main_mesh_legacy_convert_auto_smooth(*new_bmain); } }