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