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
This commit is contained in:
Falk David
2025-05-05 10:41:21 +02:00
committed by Falk David
parent d5b697b3f1
commit a7d2b7850e
14 changed files with 267 additions and 32 deletions

View File

@@ -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:

View File

@@ -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'

View File

@@ -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"

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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<const GreasePencil *>(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<GreasePencil *>(object.data);
Vector<int> 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<bke::GreasePencilComponent>().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<const ID *>(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<std::string> 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;
}

View File

@@ -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<Material *> original_materials;
const Span<Material *> eval_materials = Span{merged_layers_grease_pencil.material_array,
merged_layers_grease_pencil.material_array_num};
const Span<Material *> 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<Material *>(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<int> 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<int> 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<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
"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];
}
}

View File

@@ -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;

View File

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

View File

@@ -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,

View File

@@ -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 {

View File

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

View File

@@ -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<EditSelectionFieldInput>(data_type));
case OB_MODE_SCULPT:
case OB_MODE_SCULPT_CURVES:
case OB_MODE_SCULPT_GREASE_PENCIL:
return GField(std::make_shared<SculptSelectionFieldInput>(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));

View File

@@ -85,9 +85,9 @@ static void node_geo_exec(GeoNodeExecParams params)
}
GeometrySet geometry = params.extract_input<GeometrySet>("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<PointCloudComponent>(), ".selection", domain, field);
}
}
if (geometry.has_grease_pencil()) {
/* Grease Pencil only supports boolean selection. */
const Field<bool> field = conversions.try_convert(selection, CPPType::get<bool>());
if (ELEM(domain, AttrDomain::Point, AttrDomain::Curve)) {
bke::try_capture_field_on_geometry(
geometry.get_component_for_write<GreasePencilComponent>(),
".selection",
domain,
field);
}
}
});
params.set_output("Geometry", std::move(geometry));
}