diff --git a/source/blender/blenloader/intern/versioning_450.cc b/source/blender/blenloader/intern/versioning_450.cc index 715616a519b..ea12d948020 100644 --- a/source/blender/blenloader/intern/versioning_450.cc +++ b/source/blender/blenloader/intern/versioning_450.cc @@ -4425,6 +4425,69 @@ static void do_version_flip_node_options_to_inputs(bNodeTree *node_tree, bNode * } } +static void clamp_subdivision_node_level_input(bNodeTree &tree) +{ + blender::Map links_to_level_and_max_inputs; + LISTBASE_FOREACH (bNodeLink *, link, &tree.links) { + if (link->tosock) { + if (ELEM(blender::StringRef(link->tosock->identifier), "Level", "Max")) { + links_to_level_and_max_inputs.add(link->tosock, link); + } + } + } + LISTBASE_FOREACH_MUTABLE (bNode *, node, &tree.nodes) { + if (!ELEM(node->type_legacy, GEO_NODE_SUBDIVISION_SURFACE, GEO_NODE_SUBDIVIDE_MESH)) { + continue; + } + bNodeSocket *level_input = blender::bke::node_find_socket(*node, SOCK_IN, "Level"); + if (!level_input || level_input->type != SOCK_INT) { + continue; + } + bNodeLink *link = links_to_level_and_max_inputs.lookup_default(level_input, nullptr); + if (link) { + bNode *origin_node = link->fromnode; + if (origin_node->type_legacy == SH_NODE_CLAMP) { + bNodeSocket *max_input_socket = blender::bke::node_find_socket( + *origin_node, SOCK_IN, "Max"); + if (max_input_socket->type == SOCK_FLOAT && + !links_to_level_and_max_inputs.contains(max_input_socket)) + { + if (max_input_socket->default_value_typed()->value <= 11.0f) { + /* There is already a clamp node, so no need to add another one. */ + continue; + } + } + } + /* Insert clamp node. */ + bNode &clamp_node = version_node_add_empty(tree, "ShaderNodeClamp"); + clamp_node.parent = node->parent; + clamp_node.location[0] = node->location[0] - 25; + clamp_node.location[1] = node->location[1]; + bNodeSocket &clamp_value_input = version_node_add_socket( + tree, clamp_node, SOCK_IN, "NodeSocketFloat", "Value"); + bNodeSocket &clamp_min_input = version_node_add_socket( + tree, clamp_node, SOCK_IN, "NodeSocketFloat", "Min"); + bNodeSocket &clamp_max_input = version_node_add_socket( + tree, clamp_node, SOCK_IN, "NodeSocketFloat", "Max"); + bNodeSocket &clamp_value_output = version_node_add_socket( + tree, clamp_node, SOCK_OUT, "NodeSocketFloat", "Result"); + + static_cast(clamp_min_input.default_value)->value = 0.0f; + static_cast(clamp_max_input.default_value)->value = 11.0f; + + link->tosock = &clamp_value_input; + version_node_add_link(tree, clamp_node, clamp_value_output, *node, *level_input); + } + else { + /* Clamp value directly. */ + bNodeSocketValueInt *value = level_input->default_value_typed(); + value->value = std::clamp(value->value, 0, 11); + } + } + + version_socket_update_is_used(&tree); +} + void do_versions_after_linking_450(FileData * /*fd*/, Main *bmain) { if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 8)) { @@ -6254,6 +6317,15 @@ void blo_do_versions_450(FileData * /*fd*/, Library * /*lib*/, Main *bmain) fix_curve_nurbs_knot_mode_custom(bmain); } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 87)) { + FOREACH_NODETREE_BEGIN (bmain, tree, id) { + if (tree->type == NTREE_GEOMETRY) { + clamp_subdivision_node_level_input(*tree); + } + } + FOREACH_NODETREE_END; + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check. diff --git a/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc b/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc index 0cfdeb86cb2..22d3cd35062 100644 --- a/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc +++ b/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc @@ -2683,11 +2683,18 @@ static wmOperatorStatus grease_pencil_paste_strokes_exec(bContext *C, wmOperator const bool keep_world_transform = RNA_boolean_get(op->ptr, "keep_world_transform"); const bool paste_on_back = RNA_boolean_get(op->ptr, "paste_back"); - const Clipboard &clipboard = ensure_grease_pencil_clipboard(); + Clipboard &clipboard = ensure_grease_pencil_clipboard(); if (clipboard.layers.is_empty()) { return OPERATOR_CANCELLED; } + /* Make sure everything on the clipboard is selected, in the correct selection domain. */ + threading::parallel_for_each(clipboard.layers, [&](Clipboard::ClipboardLayer &layer) { + bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute( + layer.curves, selection_domain, CD_PROP_BOOL); + selection.finish(); + }); + if (type == PasteType::Active) { Layer *active_layer = grease_pencil.get_active_layer(); if (!active_layer) { diff --git a/source/blender/nodes/composite/nodes/node_composite_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_rgb.cc index dea3657d043..a9f5e997697 100644 --- a/source/blender/nodes/composite/nodes/node_composite_rgb.cc +++ b/source/blender/nodes/composite/nodes/node_composite_rgb.cc @@ -27,7 +27,7 @@ static void cmp_node_rgb_declare(NodeDeclarationBuilder &b) .default_value({0.5f, 0.5f, 0.5f, 1.0f}) .custom_draw([](CustomSocketDrawParams ¶ms) { uiLayoutSetAlignment(¶ms.layout, UI_LAYOUT_ALIGN_EXPAND); - uiLayout &col = params.layout.column(true); + uiLayout &col = params.layout.column(false); uiTemplateColorPicker( &col, ¶ms.socket_ptr, "default_value", true, false, false, false); col.prop(¶ms.socket_ptr, "default_value", UI_ITEM_R_SLIDER, "", ICON_NONE); diff --git a/source/blender/nodes/function/nodes/node_fn_input_color.cc b/source/blender/nodes/function/nodes/node_fn_input_color.cc index ba052b711dd..410aa8c77b8 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_color.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_color.cc @@ -15,7 +15,7 @@ static void node_declare(NodeDeclarationBuilder &b) { b.add_output("Color").custom_draw([](CustomSocketDrawParams ¶ms) { uiLayoutSetAlignment(¶ms.layout, UI_LAYOUT_ALIGN_EXPAND); - uiLayout &col = params.layout.column(true); + uiLayout &col = params.layout.column(false); uiTemplateColorPicker(&col, ¶ms.node_ptr, "value", true, false, false, true); col.prop(¶ms.node_ptr, "value", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc index ccc36fbaecc..e702c68f375 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc @@ -58,11 +58,17 @@ static void node_geo_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input("Mesh"); #ifdef WITH_OPENSUBDIV /* See CCGSUBSURF_LEVEL_MAX for max limit. */ - const int level = clamp_i(params.extract_input("Level"), 0, 11); + const int level = std::max(params.extract_input("Level"), 0); if (level == 0) { params.set_output("Mesh", std::move(geometry_set)); return; } + /* At this limit, a subdivided single triangle would be too large to be stored in #Mesh. */ + if (level >= 16) { + params.error_message_add(NodeWarningType::Error, TIP_("The subdivision level is too large")); + params.set_default_remaining_outputs(); + return; + } geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { if (const Mesh *mesh = geometry_set.get_mesh()) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 1b4c000815c..fa869d59001 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -186,12 +186,18 @@ static void node_geo_exec(GeoNodeExecParams params) const NodeGeometrySubdivisionSurface &storage = node_storage(params.node()); const int uv_smooth = storage.uv_smooth; const int boundary_smooth = storage.boundary_smooth; - const int level = std::clamp(params.extract_input("Level"), 0, 11); + const int level = std::max(params.extract_input("Level"), 0); const bool use_limit_surface = params.extract_input("Limit Surface"); if (level == 0) { params.set_output("Mesh", std::move(geometry_set)); return; } + /* At this limit, a subdivided single triangle would be too large to be stored in #Mesh. */ + if (level >= 16) { + params.error_message_add(NodeWarningType::Error, TIP_("The subdivision level is too large")); + params.set_default_remaining_outputs(); + return; + } geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { if (const Mesh *mesh = geometry_set.get_mesh()) { diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_rgb.cc index ec73580405d..eff4d1a3023 100644 --- a/source/blender/nodes/shader/nodes/node_shader_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_rgb.cc @@ -19,7 +19,7 @@ static void node_declare(NodeDeclarationBuilder &b) .default_value({0.5f, 0.5f, 0.5f, 1.0f}) .custom_draw([](CustomSocketDrawParams ¶ms) { uiLayoutSetAlignment(¶ms.layout, UI_LAYOUT_ALIGN_EXPAND); - uiLayout &col = params.layout.column(true); + uiLayout &col = params.layout.column(false); uiTemplateColorPicker( &col, ¶ms.socket_ptr, "default_value", true, false, false, false); col.prop(¶ms.socket_ptr, "default_value", UI_ITEM_R_SLIDER, "", ICON_NONE);