From a7d2b7850ef235e69ddd6d87f3f39c28260fd17e Mon Sep 17 00:00:00 2001 From: Falk David Date: Mon, 5 May 2025 10:41:21 +0200 Subject: [PATCH] Grease Pencil: Add initial support for Node Tools This adds inital Grease Pencil support for node tools. Node tools work in `Object Mode`, `Edit Mode`,`Sculpt Mode`, and `Draw Mode`. While Grease Pencil has many editing tools, including editing multiple frames at the same time, for now, node tools only allow editing the current frame. Currently, the idea is that node tools can do arbitrary changes to the drawings, but cannot do changes to the existing layer tree, e.g. changing the order of layers, removing a layer or groups, etc. All the node tool specific nodes like `Selection` and `Set Selection` are adapted to work with Grease Pencil. In `Draw Mode`, we currently interpret everything as selected. The `Active Element` node has a `Layer` mode that provides the index of the active layer (if there is one). When `Auto-Key` is used, a new keyframe is created on the current frame. Locked/invisible layers cannot be edited with node tools. Pull Request: https://projects.blender.org/blender/blender/pulls/136624 --- .../startup/bl_operators/geometry_nodes.py | 6 +- scripts/startup/bl_ui/space_node.py | 6 + scripts/startup/bl_ui/space_view3d.py | 10 ++ .../blender/blenkernel/BKE_grease_pencil.hh | 7 + .../blenkernel/intern/grease_pencil.cc | 9 ++ .../editors/geometry/node_group_operator.cc | 148 +++++++++++++++++- .../intern/grease_pencil_utils.cc | 27 ++-- .../blender/editors/object/object_modifier.cc | 12 +- source/blender/makesdna/DNA_node_types.h | 3 + .../blender/makesrna/intern/rna_nodetree.cc | 35 +++++ .../nodes/NOD_geometry_nodes_lazy_function.hh | 1 + .../nodes/node_geo_tool_active_element.cc | 14 +- .../geometry/nodes/node_geo_tool_selection.cc | 6 + .../nodes/node_geo_tool_set_selection.cc | 15 +- 14 files changed, 267 insertions(+), 32 deletions(-) diff --git a/scripts/startup/bl_operators/geometry_nodes.py b/scripts/startup/bl_operators/geometry_nodes.py index 11b2d616073..157728f2c66 100644 --- a/scripts/startup/bl_operators/geometry_nodes.py +++ b/scripts/startup/bl_operators/geometry_nodes.py @@ -50,12 +50,16 @@ def geometry_node_group_empty_tool_new(context): group.is_type_curve = True elif ob_type == 'POINTCLOUD': group.is_type_pointcloud = True + elif ob_type == 'GREASEPENCIL': + group.is_type_grease_pencil = True else: group.is_type_mesh = True mode = ob.mode if ob else 'OBJECT' - if mode in {'SCULPT', 'SCULPT_CURVES'}: + if mode in {'SCULPT', 'SCULPT_CURVES', 'SCULPT_GREASE_PENCIL'}: group.is_mode_sculpt = True + elif mode == 'PAINT_GREASE_PENCIL': + group.is_mode_paint = True elif mode == 'EDIT': group.is_mode_edit = True else: diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index 96dbac34810..67249b0be5f 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -463,6 +463,7 @@ class NODE_PT_geometry_node_tool_object_types(Panel): types = [ ("is_type_mesh", "Mesh", 'MESH_DATA'), ("is_type_curve", "Hair Curves", 'CURVES_DATA'), + ("is_type_grease_pencil", "Grease Pencil", 'OUTLINER_OB_GREASEPENCIL'), ("is_type_pointcloud", "Point Cloud", 'POINTCLOUD_DATA'), ] @@ -499,6 +500,11 @@ class NODE_PT_geometry_node_tool_mode(Panel): row.label(text=name, icon=icon) row.prop(group, prop, text="") + if group.is_type_grease_pencil: + row = col.row(align=True) + row.label(text="Draw Mode", icon='GREASEPENCIL') + row.prop(group, "is_mode_paint", text="") + class NODE_PT_geometry_node_tool_options(Panel): bl_space_type = 'NODE_EDITOR' diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index bd6d53bbb7c..0e104f7604a 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -1212,6 +1212,7 @@ class VIEW3D_MT_editor_menus(Menu): elif mode_string == 'EDIT_GREASE_PENCIL': layout.menu("VIEW3D_MT_edit_greasepencil_point") layout.menu("VIEW3D_MT_edit_greasepencil_stroke") + layout.template_node_operator_asset_root_items() elif obj: if mode_string not in {'PAINT_TEXTURE', 'SCULPT_CURVES', 'SCULPT_GREASE_PENCIL', 'VERTEX_GREASE_PENCIL'}: @@ -1236,6 +1237,7 @@ class VIEW3D_MT_editor_menus(Menu): ) if is_selection_mask: layout.menu("VIEW3D_MT_select_edit_grease_pencil") + layout.template_node_operator_asset_root_items() else: layout.template_node_operator_asset_root_items() @@ -2225,6 +2227,8 @@ class VIEW3D_MT_select_edit_grease_pencil(Menu): props.amount_start = 0 props.amount_end = 1 + layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label) + class VIEW3D_MT_paint_grease_pencil(Menu): bl_label = "Draw" @@ -5777,6 +5781,8 @@ class VIEW3D_MT_edit_greasepencil(Menu): layout.menu("VIEW3D_MT_edit_greasepencil_delete") + layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label) + class VIEW3D_MT_edit_greasepencil_stroke(Menu): bl_label = "Stroke" @@ -5825,6 +5831,8 @@ class VIEW3D_MT_edit_greasepencil_stroke(Menu): layout.operator("grease_pencil.reset_uvs") + layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label) + class VIEW3D_MT_edit_greasepencil_point(Menu): bl_label = "Point" @@ -5846,6 +5854,8 @@ class VIEW3D_MT_edit_greasepencil_point(Menu): layout.operator_menu_enum("grease_pencil.set_handle_type", property="type") + layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label) + class VIEW3D_MT_edit_curves_add(Menu): bl_label = "Add" diff --git a/source/blender/blenkernel/BKE_grease_pencil.hh b/source/blender/blenkernel/BKE_grease_pencil.hh index 704ef2ebb1a..cc2acab50fc 100644 --- a/source/blender/blenkernel/BKE_grease_pencil.hh +++ b/source/blender/blenkernel/BKE_grease_pencil.hh @@ -899,6 +899,13 @@ TREENODE_COMMON_METHODS_FORWARD_IMPL(LayerGroup); const AttributeAccessorFunctions &get_attribute_accessor_functions(); +/** + * Renames layers with empty names to "Layer". + * \note While original data should not have layers with empty names, we allow layer names to be + * empty in evaluated geometry. + */ +void ensure_non_empty_layer_names(Main &bmain, GreasePencil &grease_pencil); + } // namespace greasepencil class GreasePencilRuntime { diff --git a/source/blender/blenkernel/intern/grease_pencil.cc b/source/blender/blenkernel/intern/grease_pencil.cc index 549f6e42ea3..120cbb59b7e 100644 --- a/source/blender/blenkernel/intern/grease_pencil.cc +++ b/source/blender/blenkernel/intern/grease_pencil.cc @@ -1940,6 +1940,15 @@ void LayerGroup::update_from_dna_read() } } +void ensure_non_empty_layer_names(Main &bmain, GreasePencil &grease_pencil) +{ + for (bke::greasepencil::Layer *layer : grease_pencil.layers_for_write()) { + if (layer->name().is_empty()) { + grease_pencil.rename_node(bmain, layer->as_node(), DATA_("Layer")); + } + } +} + } // namespace blender::bke::greasepencil namespace blender::bke { diff --git a/source/blender/editors/geometry/node_group_operator.cc b/source/blender/editors/geometry/node_group_operator.cc index d638f6191ae..f26af1472c9 100644 --- a/source/blender/editors/geometry/node_group_operator.cc +++ b/source/blender/editors/geometry/node_group_operator.cc @@ -6,12 +6,14 @@ * \ingroup edcurves */ +#include "BLI_index_mask.hh" #include "BLI_listbase.h" #include "BLI_path_utils.hh" #include "BLI_rect.h" #include "BLI_string.h" #include "ED_curves.hh" +#include "ED_grease_pencil.hh" #include "ED_object.hh" #include "ED_screen.hh" #include "ED_select_utils.hh" @@ -27,6 +29,7 @@ #include "BKE_customdata.hh" #include "BKE_editmesh.hh" #include "BKE_geometry_set.hh" +#include "BKE_grease_pencil.hh" #include "BKE_layer.hh" #include "BKE_lib_id.hh" #include "BKE_lib_query.hh" @@ -253,12 +256,22 @@ static bke::GeometrySet get_original_geometry_eval_copy(Depsgraph &depsgraph, orig_mesh_states.append_as(*mesh_copy); return bke::GeometrySet::from_mesh(mesh_copy); } + case OB_GREASE_PENCIL: { + const GreasePencil *grease_pencil = static_cast(object.data); + if (const bke::greasepencil::Layer *active_layer = grease_pencil->get_active_layer()) { + operator_data.active_layer_index = *grease_pencil->get_layer_index(*active_layer); + } + GreasePencil *grease_pencil_copy = BKE_grease_pencil_copy_for_eval(grease_pencil); + grease_pencil_copy->runtime->eval_frame = int(DEG_get_ctime(&depsgraph)); + return bke::GeometrySet::from_grease_pencil(grease_pencil_copy); + } default: return {}; } } -static void store_result_geometry(const wmOperator &op, +static void store_result_geometry(const bContext &C, + const wmOperator &op, const Depsgraph &depsgraph, Main &bmain, Scene &scene, @@ -336,6 +349,59 @@ static void store_result_geometry(const wmOperator &op, } break; } + case OB_GREASE_PENCIL: { + const int eval_frame = int(DEG_get_ctime(&depsgraph)); + + GreasePencil &grease_pencil = *static_cast(object.data); + Vector editable_layer_indices; + for (const int layer_i : grease_pencil.layers().index_range()) { + const bke::greasepencil::Layer &layer = grease_pencil.layer(layer_i); + if (!layer.is_editable()) { + continue; + } + editable_layer_indices.append(layer_i); + } + + bool inserted_new_keyframe = false; + for (const int layer_i : editable_layer_indices) { + bke::greasepencil::Layer &layer = grease_pencil.layer(layer_i); + /* TODO: For now, we always create a blank keyframe, but it might be good to expose this as + * an option and allow to duplicate the previous key. */ + const bool duplicate_previous_key = false; + ed::greasepencil::ensure_active_keyframe( + scene, grease_pencil, layer, duplicate_previous_key, inserted_new_keyframe); + } + GreasePencil *new_grease_pencil = + geometry.get_component_for_write().get_for_write(); + if (!new_grease_pencil) { + /* Clear the Grease Pencil geometry. */ + for (const int layer_i : editable_layer_indices) { + bke::greasepencil::Layer &layer = grease_pencil.layer(layer_i); + if (bke::greasepencil::Drawing *drawing_orig = grease_pencil.get_drawing_at(layer, + eval_frame)) + { + drawing_orig->strokes_for_write() = {}; + drawing_orig->tag_topology_changed(); + } + } + } + else { + IndexMaskMemory memory; + const IndexMask editable_layers = IndexMask::from_indices(editable_layer_indices.as_span(), + memory); + ed::greasepencil::apply_eval_grease_pencil_data( + *new_grease_pencil, eval_frame, editable_layers, grease_pencil); + + /* There might be layers with empty names after evaluation. Make sure to rename them. */ + bke::greasepencil::ensure_non_empty_layer_names(bmain, grease_pencil); + BKE_object_material_from_eval_data(&bmain, &object, &new_grease_pencil->id); + } + + DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY); + if (inserted_new_keyframe) { + WM_event_add_notifier(&C, NC_GPENCIL | NA_EDITED, nullptr); + } + } } } @@ -473,7 +539,7 @@ static void replace_inputs_evaluated_data_blocks( static bool object_has_editable_data(const Main &bmain, const Object &object) { - if (!ELEM(object.type, OB_CURVES, OB_POINTCLOUD, OB_MESH)) { + if (!ELEM(object.type, OB_CURVES, OB_POINTCLOUD, OB_MESH, OB_GREASE_PENCIL)) { return false; } if (!BKE_id_is_editable(&bmain, static_cast(object.data))) { @@ -635,7 +701,7 @@ static wmOperatorStatus run_node_group_exec(bContext *C, wmOperator *op) std::move(geometry_orig)); store_result_geometry( - *op, *depsgraph_active, *bmain, *scene, *object, rv3d, std::move(new_geometry)); + *C, *op, *depsgraph_active, *bmain, *scene, *object, rv3d, std::move(new_geometry)); WM_event_add_notifier(C, NC_GEOM | ND_DATA, object->data); } @@ -1066,6 +1132,20 @@ static GeometryNodeAssetTraitFlag asset_flag_for_context(const ObjectType type, } break; } + case OB_GREASE_PENCIL: { + switch (mode) { + case OB_MODE_OBJECT: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_OBJECT | GEO_NODE_ASSET_GREASE_PENCIL); + case OB_MODE_EDIT: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_EDIT | GEO_NODE_ASSET_GREASE_PENCIL); + case OB_MODE_SCULPT_GREASE_PENCIL: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_SCULPT | GEO_NODE_ASSET_GREASE_PENCIL); + case OB_MODE_PAINT_GREASE_PENCIL: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_PAINT | GEO_NODE_ASSET_GREASE_PENCIL); + default: + break; + } + } default: break; } @@ -1131,6 +1211,28 @@ static asset::AssetItemTree *get_static_item_tree(const ObjectType type, const e return nullptr; } } + case OB_GREASE_PENCIL: { + switch (mode) { + case OB_MODE_OBJECT: { + static asset::AssetItemTree tree; + return &tree; + } + case OB_MODE_EDIT: { + static asset::AssetItemTree tree; + return &tree; + } + case OB_MODE_SCULPT_GREASE_PENCIL: { + static asset::AssetItemTree tree; + return &tree; + } + case OB_MODE_PAINT_GREASE_PENCIL: { + static asset::AssetItemTree tree; + return &tree; + } + default: + return nullptr; + } + } default: return nullptr; } @@ -1143,9 +1245,13 @@ static asset::AssetItemTree *get_static_item_tree(const Object &active_object) void clear_operator_asset_trees() { - for (const ObjectType type : {OB_MESH, OB_CURVES, OB_POINTCLOUD}) { - for (const eObjectMode mode : - {OB_MODE_OBJECT, OB_MODE_EDIT, OB_MODE_SCULPT, OB_MODE_SCULPT_CURVES}) + for (const ObjectType type : {OB_MESH, OB_CURVES, OB_POINTCLOUD, OB_GREASE_PENCIL}) { + for (const eObjectMode mode : {OB_MODE_OBJECT, + OB_MODE_EDIT, + OB_MODE_SCULPT, + OB_MODE_SCULPT_CURVES, + OB_MODE_SCULPT_GREASE_PENCIL, + OB_MODE_PAINT_GREASE_PENCIL}) { if (asset::AssetItemTree *tree = get_static_item_tree(type, mode)) { tree->dirty = true; @@ -1243,6 +1349,36 @@ static Set get_builtin_menus(const ObjectType object_type, const eO default: break; } + break; + case OB_GREASE_PENCIL: { + switch (mode) { + case OB_MODE_OBJECT: + menus.add_new("View"); + menus.add_new("Select"); + menus.add_new("Add"); + menus.add_new("Object"); + menus.add_new("Object/Apply"); + menus.add_new("Object/Convert"); + menus.add_new("Object/Quick Effects"); + break; + case OB_MODE_EDIT: + menus.add_new("View"); + menus.add_new("Select"); + menus.add_new("Grease Pencil"); + menus.add_new("Stroke"); + menus.add_new("Point"); + break; + case OB_MODE_SCULPT_GREASE_PENCIL: + menus.add_new("View"); + break; + case OB_MODE_PAINT_GREASE_PENCIL: + menus.add_new("View"); + menus.add_new("Draw"); + break; + default: + break; + } + } default: break; } diff --git a/source/blender/editors/grease_pencil/intern/grease_pencil_utils.cc b/source/blender/editors/grease_pencil/intern/grease_pencil_utils.cc index 63d90972de4..fb136d4c2fe 100644 --- a/source/blender/editors/grease_pencil/intern/grease_pencil_utils.cc +++ b/source/blender/editors/grease_pencil/intern/grease_pencil_utils.cc @@ -31,6 +31,8 @@ #include "DNA_scene_types.h" #include "DNA_view3d_types.h" +#include "DEG_depsgraph_query.hh" + #include "GEO_merge_layers.hh" #include "RNA_prototypes.hh" @@ -1873,21 +1875,23 @@ void apply_eval_grease_pencil_data(const GreasePencil &eval_grease_pencil, /* Get the original material pointers from the result geometry. */ VectorSet original_materials; - const Span eval_materials = Span{merged_layers_grease_pencil.material_array, - merged_layers_grease_pencil.material_array_num}; + const Span eval_materials = Span{eval_grease_pencil.material_array, + eval_grease_pencil.material_array_num}; for (Material *eval_material : eval_materials) { - if (eval_material != nullptr && eval_material->id.orig_id != nullptr) { - original_materials.add_new(reinterpret_cast(eval_material->id.orig_id)); + if (!eval_material) { + return; } + original_materials.add(DEG_get_original(eval_material)); } /* Build material indices mapping. This maps the materials indices on the original geometry to - * the material indices used in the result geometry. The material indices for the drawings in the - * result geometry are already correct, but this might not be the case for all drawings in the - * original geometry (like for drawings that are not visible on the frame that the data is + * the material indices used in the result geometry. The material indices for the drawings in + * the result geometry are already correct, but this might not be the case for all drawings in + * the original geometry (like for drawings that are not visible on the frame that the data is * being applied on). */ - Array material_indices_map(orig_grease_pencil.material_array_num); - for (const int mat_i : IndexRange(orig_grease_pencil.material_array_num)) { + const IndexRange orig_material_indices = IndexRange(orig_grease_pencil.material_array_num); + Array material_indices_map(orig_grease_pencil.material_array_num, -1); + for (const int mat_i : orig_material_indices) { Material *material = orig_grease_pencil.material_array[mat_i]; const int map_index = original_materials.index_of_try(material); if (map_index != -1) { @@ -1897,8 +1901,7 @@ void apply_eval_grease_pencil_data(const GreasePencil &eval_grease_pencil, /* Remap material indices for all other drawings. */ if (!material_indices_map.is_empty() && - !array_utils::indices_are_range(material_indices_map, - IndexRange(orig_grease_pencil.material_array_num))) + !array_utils::indices_are_range(material_indices_map, orig_material_indices)) { for (GreasePencilDrawingBase *base : orig_grease_pencil.drawings()) { if (base->type != GP_DRAWING) { @@ -1916,7 +1919,7 @@ void apply_eval_grease_pencil_data(const GreasePencil &eval_grease_pencil, SpanAttributeWriter material_indices = attributes.lookup_or_add_for_write_span( "material_index", AttrDomain::Curve); for (int &material_index : material_indices.span) { - if (material_index >= 0 && material_index < material_indices_map.size()) { + if (material_indices_map.index_range().contains(material_index)) { material_index = material_indices_map[material_index]; } } diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index fe0e47a3e10..f0f826c732e 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -978,11 +978,7 @@ static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph, Main *bmain = DEG_get_bmain(depsgraph); /* There might be layers with empty names after evaluation. Make sure to rename them. */ - for (Layer *layer : grease_pencil_orig.layers_for_write()) { - if (layer->name().is_empty()) { - grease_pencil_orig.rename_node(*bmain, layer->as_node(), DATA_("Layer")); - } - } + bke::greasepencil::ensure_non_empty_layer_names(*bmain, grease_pencil_result); BKE_object_material_from_eval_data(bmain, ob, &grease_pencil_result.id); return true; } @@ -1062,11 +1058,7 @@ static bool apply_grease_pencil_for_modifier_all_keyframes(Depsgraph *depsgraph, BKE_scene_graph_update_for_newframe(depsgraph); /* There might be layers with empty names after evaluation. Make sure to rename them. */ - for (Layer *layer : grease_pencil_orig.layers_for_write()) { - if (layer->name().is_empty()) { - grease_pencil_orig.rename_node(*bmain, layer->as_node(), DATA_("Layer")); - } - } + bke::greasepencil::ensure_non_empty_layer_names(*bmain, grease_pencil_orig); WM_cursor_wait(false); return changed; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 6500f8d2c9d..8c2192b41aa 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1018,6 +1018,9 @@ typedef enum GeometryNodeAssetTraitFlag { GEO_NODE_ASSET_MODIFIER = (1 << 6), GEO_NODE_ASSET_OBJECT = (1 << 7), GEO_NODE_ASSET_WAIT_FOR_CURSOR = (1 << 8), + GEO_NODE_ASSET_GREASE_PENCIL = (1 << 9), + /* Only used by Grease Pencil for now. */ + GEO_NODE_ASSET_PAINT = (1 << 10), } GeometryNodeAssetTraitFlag; ENUM_OPERATORS(GeometryNodeAssetTraitFlag, GEO_NODE_ASSET_WAIT_FOR_CURSOR); diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index 9dd1bb63fa9..0153c8deb75 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -2207,6 +2207,15 @@ static void rna_GeometryNodeTree_is_mode_sculpt_set(PointerRNA *ptr, bool value) geometry_node_asset_trait_flag_set(ptr, GEO_NODE_ASSET_SCULPT, value); } +static bool rna_GeometryNodeTree_is_mode_paint_get(PointerRNA *ptr) +{ + return geometry_node_asset_trait_flag_get(ptr, GEO_NODE_ASSET_PAINT); +} +static void rna_GeometryNodeTree_is_mode_paint_set(PointerRNA *ptr, bool value) +{ + geometry_node_asset_trait_flag_set(ptr, GEO_NODE_ASSET_PAINT, value); +} + static bool rna_GeometryNodeTree_is_type_mesh_get(PointerRNA *ptr) { return geometry_node_asset_trait_flag_get(ptr, GEO_NODE_ASSET_MESH); @@ -2243,6 +2252,15 @@ static void rna_GeometryNodeTree_use_wait_for_click_set(PointerRNA *ptr, bool va geometry_node_asset_trait_flag_set(ptr, GEO_NODE_ASSET_WAIT_FOR_CURSOR, value); } +static bool rna_GeometryNodeTree_is_type_grease_pencil_get(PointerRNA *ptr) +{ + return geometry_node_asset_trait_flag_get(ptr, GEO_NODE_ASSET_GREASE_PENCIL); +} +static void rna_GeometryNodeTree_is_type_grease_pencil_set(PointerRNA *ptr, bool value) +{ + geometry_node_asset_trait_flag_set(ptr, GEO_NODE_ASSET_GREASE_PENCIL, value); +} + static bool random_value_type_supported(const EnumPropertyItem *item) { return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_BOOL, CD_PROP_INT32); @@ -13357,6 +13375,14 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna) prop, "rna_GeometryNodeTree_is_mode_sculpt_get", "rna_GeometryNodeTree_is_mode_sculpt_set"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset"); + prop = RNA_def_property(srna, "is_mode_paint", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_PAINT); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Paint", "The node group is used in paint mode"); + RNA_def_property_boolean_funcs( + prop, "rna_GeometryNodeTree_is_mode_paint_get", "rna_GeometryNodeTree_is_mode_paint_set"); + RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset"); + prop = RNA_def_property(srna, "is_type_mesh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_MESH); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -13392,6 +13418,15 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna) "rna_GeometryNodeTree_use_wait_for_click_get", "rna_GeometryNodeTree_use_wait_for_click_set"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset"); + + prop = RNA_def_property(srna, "is_type_grease_pencil", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_GREASE_PENCIL); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Grease Pencil", "The node group is used for Grease Pencil"); + RNA_def_property_boolean_funcs(prop, + "rna_GeometryNodeTree_is_type_grease_pencil_get", + "rna_GeometryNodeTree_is_type_grease_pencil_set"); + RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset"); } static StructRNA *define_specific_node(BlenderRNA *brna, diff --git a/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh b/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh index b7a4f72a390..f87b75fe9d5 100644 --- a/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh +++ b/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh @@ -207,6 +207,7 @@ struct GeoNodesOperatorData { int active_point_index = -1; int active_edge_index = -1; int active_face_index = -1; + int active_layer_index = -1; }; struct GeoNodesCallData { diff --git a/source/blender/nodes/geometry/nodes/node_geo_tool_active_element.cc b/source/blender/nodes/geometry/nodes/node_geo_tool_active_element.cc index d1235063b87..8f953d2e10b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_tool_active_element.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_tool_active_element.cc @@ -60,6 +60,10 @@ static void node_exec(GeoNodeExecParams params) params.set_output("Exists", operator_data->active_face_index >= 0); params.set_output("Index", std::max(0, operator_data->active_face_index)); break; + case AttrDomain::Layer: + params.set_output("Exists", operator_data->active_layer_index >= 0); + params.set_output("Index", std::max(0, operator_data->active_layer_index)); + break; default: params.set_default_remaining_outputs(); BLI_assert_unreachable(); @@ -69,11 +73,19 @@ static void node_exec(GeoNodeExecParams params) static void node_rna(StructRNA *srna) { + static const EnumPropertyItem rna_domain_items[] = { + {int(AttrDomain::Point), "POINT", 0, "Point", ""}, + {int(AttrDomain::Edge), "EDGE", 0, "Edge", ""}, + {int(AttrDomain::Face), "FACE", 0, "Face", ""}, + {int(AttrDomain::Layer), "LAYER", 0, "Layer", ""}, + {0, nullptr, 0, nullptr, nullptr}, + }; + RNA_def_node_enum(srna, "domain", "Domain", "", - rna_enum_attribute_domain_only_mesh_no_corner_items, + rna_domain_items, NOD_inline_enum_accessors(custom1), int(AttrDomain::Point)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_tool_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_tool_selection.cc index 9ad71366f44..9e0ed413f60 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_tool_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_tool_selection.cc @@ -86,6 +86,7 @@ class EditSelectionFieldInput final : public bke::GeometryFieldInput { switch (context.type()) { case GeometryComponent::Type::Curve: case GeometryComponent::Type::PointCloud: + case GeometryComponent::Type::GreasePencil: return *attributes.lookup_or_default( ".selection", domain, data_type, true_value(data_type)); case GeometryComponent::Type::Mesh: @@ -114,6 +115,7 @@ class SculptSelectionFieldInput final : public bke::GeometryFieldInput { switch (context.type()) { case GeometryComponent::Type::Curve: case GeometryComponent::Type::PointCloud: + case GeometryComponent::Type::GreasePencil: return *attributes.lookup_or_default( ".selection", domain, data_type, true_value(data_type)); case GeometryComponent::Type::Mesh: { @@ -156,7 +158,11 @@ static GField get_selection_field(const eObjectMode object_mode, const eCustomDa return GField(std::make_shared(data_type)); case OB_MODE_SCULPT: case OB_MODE_SCULPT_CURVES: + case OB_MODE_SCULPT_GREASE_PENCIL: return GField(std::make_shared(data_type)); + case OB_MODE_PAINT_GREASE_PENCIL: + return fn::make_constant_field(*bke::custom_data_type_to_cpp_type(data_type), + true_value(data_type)); default: return fn::make_constant_field(*bke::custom_data_type_to_cpp_type(data_type), false_value(data_type)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_tool_set_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_tool_set_selection.cc index 9e2a684c6b2..3527a3ce639 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_tool_set_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_tool_set_selection.cc @@ -85,9 +85,9 @@ static void node_geo_exec(GeoNodeExecParams params) } GeometrySet geometry = params.extract_input("Geometry"); const eObjectMode mode = params.user_data()->call_data->operator_data->mode; - if (mode == OB_MODE_OBJECT) { + if (ELEM(mode, OB_MODE_OBJECT, OB_MODE_PAINT_GREASE_PENCIL)) { params.error_message_add(NodeWarningType::Error, - "Selection control is not supported in object mode"); + "Selection control is not supported in this mode"); params.set_output("Geometry", std::move(geometry)); return; } @@ -167,6 +167,17 @@ static void node_geo_exec(GeoNodeExecParams params) geometry.get_component_for_write(), ".selection", domain, field); } } + if (geometry.has_grease_pencil()) { + /* Grease Pencil only supports boolean selection. */ + const Field field = conversions.try_convert(selection, CPPType::get()); + if (ELEM(domain, AttrDomain::Point, AttrDomain::Curve)) { + bke::try_capture_field_on_geometry( + geometry.get_component_for_write(), + ".selection", + domain, + field); + } + } }); params.set_output("Geometry", std::move(geometry)); }