diff --git a/scripts/startup/bl_operators/geometry_nodes.py b/scripts/startup/bl_operators/geometry_nodes.py index 088bf09a2fb..183a4ef2d8e 100644 --- a/scripts/startup/bl_operators/geometry_nodes.py +++ b/scripts/startup/bl_operators/geometry_nodes.py @@ -55,11 +55,13 @@ def geometry_node_group_empty_tool_new(context): else: group.is_type_mesh = True - mode = context.object.mode if context.object else 'EDIT' + mode = context.object.mode if context.object else 'OBJECT' if mode in {'SCULPT', 'SCULPT_CURVES'}: group.is_mode_sculpt = True - else: + elif mode == 'EDIT': group.is_mode_edit = True + else: + group.is_mode_object = True return group diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index 35b75057acd..0063eab4725 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -472,6 +472,7 @@ class NODE_PT_geometry_node_tool_mode(Panel): group = snode.node_tree modes = ( + ("is_mode_object", "Object Mode", 'OBJECT_DATAMODE'), ("is_mode_edit", "Edit Mode", 'EDITMODE_HLT'), ("is_mode_sculpt", "Sculpt Mode", 'SCULPTMODE_HLT'), ) diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 3c822a70316..8af5a1067cf 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -1169,9 +1169,12 @@ class VIEW3D_MT_editor_menus(Menu): layout.menu("VIEW3D_MT_select_sculpt_curves") layout.menu("VIEW3D_MT_sculpt_curves") layout.template_node_operator_asset_root_items() + else: + layout.template_node_operator_asset_root_items() else: layout.menu("VIEW3D_MT_object") + layout.template_node_operator_asset_root_items() # ********** Menu ********** @@ -2743,6 +2746,8 @@ class VIEW3D_MT_object(Menu): layout.operator("object.delete", text="Delete").use_global = False layout.operator("object.delete", text="Delete Global").use_global = True + layout.template_node_operator_asset_menu_items(catalog_path="Object") + class VIEW3D_MT_object_animation(Menu): bl_label = "Animation" @@ -3021,6 +3026,8 @@ class VIEW3D_MT_object_context_menu(Menu): layout.operator_context = 'EXEC_REGION_WIN' layout.operator("object.delete", text="Delete").use_global = False + layout.template_node_operator_asset_menu_items(catalog_path="Object") + class VIEW3D_MT_object_shading(Menu): # XXX, this menu is a place to store shading operator in object mode @@ -3098,6 +3105,8 @@ class VIEW3D_MT_object_apply(Menu): text="Parent Inverse", text_ctxt=i18n_contexts.default) + layout.template_node_operator_asset_menu_items(catalog_path="Object/Apply") + class VIEW3D_MT_object_parent(Menu): bl_label = "Parent" @@ -3180,6 +3189,7 @@ class VIEW3D_MT_object_quick_effects(Menu): layout.operator("object.quick_explode") layout.operator("object.quick_smoke") layout.operator("object.quick_liquid") + layout.template_node_operator_asset_menu_items(catalog_path="Object/Quick Effects") class VIEW3D_MT_object_showhide(Menu): @@ -3271,6 +3281,8 @@ class VIEW3D_MT_object_convert(Menu): if ob and ob.type == 'CURVES': layout.operator("curves.convert_to_particle_system", text="Particle System") + + layout.template_node_operator_asset_menu_items(catalog_path="Object/Convert") class VIEW3D_MT_make_links(Menu): diff --git a/source/blender/editors/geometry/node_group_operator.cc b/source/blender/editors/geometry/node_group_operator.cc index 79b2b85aa32..cbaa4014ddb 100644 --- a/source/blender/editors/geometry/node_group_operator.cc +++ b/source/blender/editors/geometry/node_group_operator.cc @@ -287,6 +287,39 @@ static IDProperty *replace_inputs_evaluated_data_blocks(const IDProperty &op_pro return properties; } +static bool object_has_editable_data(const Main &bmain, const Object &object) +{ + if (!ELEM(object.type, OB_CURVES, OB_POINTCLOUD, OB_MESH)) { + return false; + } + if (!BKE_id_is_editable(&bmain, static_cast(object.data))) { + return false; + } + return true; +} + +static Vector gather_supported_objects(const bContext &C, + const Main &bmain, + const eObjectMode mode) +{ + Vector objects; + Set unique_object_data; + CTX_DATA_BEGIN (&C, Object *, object, selected_objects) { + if (object->mode != mode) { + continue; + } + if (!unique_object_data.add(static_cast(object->data))) { + continue; + } + if (!object_has_editable_data(bmain, *object)) { + continue; + } + objects.append(object); + } + CTX_DATA_END; + return objects; +} + static int run_node_group_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -296,9 +329,6 @@ static int run_node_group_exec(bContext *C, wmOperator *op) if (!active_object) { return OPERATOR_CANCELLED; } - if (active_object->mode == OB_MODE_OBJECT) { - return OPERATOR_CANCELLED; - } const eObjectMode mode = eObjectMode(active_object->mode); const bNodeTree *node_tree_orig = get_node_group(*C, *op->ptr, op->reports); @@ -306,13 +336,10 @@ static int run_node_group_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data( - scene, view_layer, CTX_wm_view3d(C), &objects_len, mode); - BLI_SCOPED_DEFER([&]() { MEM_SAFE_FREE(objects); }); + const Vector objects = gather_supported_objects(*C, *bmain, mode); Depsgraph *depsgraph = build_depsgraph_from_indirect_ids( - *bmain, *scene, *view_layer, *node_tree_orig, {objects, objects_len}, *op->properties); + *bmain, *scene, *view_layer, *node_tree_orig, objects, *op->properties); DEG_evaluate_on_refresh(depsgraph); BLI_SCOPED_DEFER([&]() { DEG_graph_free(depsgraph); }); @@ -348,11 +375,9 @@ static int run_node_group_exec(bContext *C, wmOperator *op) OperatorComputeContext compute_context(op->type->idname); - for (Object *object : Span(objects, objects_len)) { - if (!ELEM(object->type, OB_CURVES, OB_POINTCLOUD, OB_MESH)) { - continue; - } + for (Object *object : objects) { nodes::GeoNodesOperatorData operator_eval_data{}; + operator_eval_data.mode = mode; operator_eval_data.depsgraph = depsgraph; operator_eval_data.self_object = DEG_get_evaluated_object(depsgraph, object); operator_eval_data.scene = DEG_get_evaluated_scene(depsgraph); @@ -600,72 +625,138 @@ static bool asset_menu_poll(const bContext *C, MenuType * /*mt*/) return CTX_wm_view3d(C); } -static GeometryNodeAssetTraitFlag asset_flag_for_context(const eContextObjectMode ctx_mode) +static GeometryNodeAssetTraitFlag asset_flag_for_context(const ObjectType type, + const eObjectMode mode) { - switch (ctx_mode) { - case CTX_MODE_EDIT_MESH: - return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_EDIT | GEO_NODE_ASSET_MESH); - case CTX_MODE_EDIT_CURVES: - return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_EDIT | GEO_NODE_ASSET_CURVE); - case CTX_MODE_EDIT_POINT_CLOUD: - return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_EDIT | GEO_NODE_ASSET_POINT_CLOUD); - case CTX_MODE_SCULPT: - return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_SCULPT | GEO_NODE_ASSET_MESH); - case CTX_MODE_SCULPT_CURVES: - return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_SCULPT | GEO_NODE_ASSET_CURVE); + switch (type) { + case OB_MESH: { + switch (mode) { + case OB_MODE_OBJECT: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_OBJECT | GEO_NODE_ASSET_MESH); + case OB_MODE_EDIT: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_EDIT | GEO_NODE_ASSET_MESH); + case OB_MODE_SCULPT: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_SCULPT | GEO_NODE_ASSET_MESH); + default: + break; + } + break; + } + case OB_CURVES: { + switch (mode) { + case OB_MODE_OBJECT: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_OBJECT | GEO_NODE_ASSET_CURVE); + case OB_MODE_EDIT: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_EDIT | GEO_NODE_ASSET_CURVE); + case OB_MODE_SCULPT_CURVES: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_SCULPT | GEO_NODE_ASSET_CURVE); + default: + break; + } + break; + } + case OB_POINTCLOUD: { + switch (mode) { + case OB_MODE_OBJECT: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_OBJECT | GEO_NODE_ASSET_POINT_CLOUD); + case OB_MODE_EDIT: + return (GEO_NODE_ASSET_TOOL | GEO_NODE_ASSET_EDIT | GEO_NODE_ASSET_POINT_CLOUD); + default: + break; + } + break; + } default: - BLI_assert_unreachable(); - return GeometryNodeAssetTraitFlag(0); + break; } + BLI_assert_unreachable(); + return GeometryNodeAssetTraitFlag(0); } -static asset::AssetItemTree *get_static_item_tree(const eContextObjectMode mode) +static GeometryNodeAssetTraitFlag asset_flag_for_context(const Object &active_object) { - switch (mode) { - case CTX_MODE_EDIT_MESH: { - static asset::AssetItemTree tree; - return &tree; + return asset_flag_for_context(ObjectType(active_object.type), eObjectMode(active_object.mode)); +} + +static asset::AssetItemTree *get_static_item_tree(const ObjectType type, const eObjectMode mode) +{ + switch (type) { + case OB_MESH: { + 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: { + static asset::AssetItemTree tree; + return &tree; + } + default: + return nullptr; + } } - case CTX_MODE_EDIT_CURVES: { - static asset::AssetItemTree tree; - return &tree; + case OB_CURVES: { + 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_CURVES: { + static asset::AssetItemTree tree; + return &tree; + } + default: + return nullptr; + } } - case CTX_MODE_EDIT_POINT_CLOUD: { - static asset::AssetItemTree tree; - return &tree; - } - case CTX_MODE_SCULPT: { - static asset::AssetItemTree tree; - return &tree; - } - case CTX_MODE_SCULPT_CURVES: { - static asset::AssetItemTree tree; - return &tree; + case OB_POINTCLOUD: { + switch (mode) { + case OB_MODE_OBJECT: { + static asset::AssetItemTree tree; + return &tree; + } + case OB_MODE_EDIT: { + static asset::AssetItemTree tree; + return &tree; + } + default: + return nullptr; + } } default: return nullptr; } } -static asset::AssetItemTree *get_static_item_tree(const bContext &C) +static asset::AssetItemTree *get_static_item_tree(const Object &active_object) { - return get_static_item_tree(eContextObjectMode(CTX_data_mode_enum(&C))); + return get_static_item_tree(ObjectType(active_object.type), eObjectMode(active_object.mode)); } void clear_operator_asset_trees() { - for (const int mode : IndexRange(CTX_MODE_NUM)) { - if (asset::AssetItemTree *tree = get_static_item_tree(eContextObjectMode(mode))) - *tree = {}; + for (const ObjectType type : {OB_MESH, OB_CURVES, OB_POINTCLOUD}) { + for (const eObjectMode mode : {OB_MODE_OBJECT, OB_MODE_EDIT, OB_MODE_SCULPT_CURVES}) { + if (asset::AssetItemTree *tree = get_static_item_tree(type, mode)) { + *tree = {}; + } + } } } -static asset::AssetItemTree build_catalog_tree(const bContext &C) +static asset::AssetItemTree build_catalog_tree(const bContext &C, const Object &active_object) { - const eContextObjectMode ctx_mode = eContextObjectMode(CTX_data_mode_enum(&C)); AssetFilterSettings type_filter{}; type_filter.id_types = FILTER_ID_NT; - const GeometryNodeAssetTraitFlag flag = asset_flag_for_context(ctx_mode); + const GeometryNodeAssetTraitFlag flag = asset_flag_for_context(active_object); auto meta_data_filter = [&](const AssetMetaData &meta_data) { const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&meta_data, "type"); if (tree_type == nullptr || IDP_Int(tree_type) != NTREE_GEOMETRY) { @@ -703,6 +794,15 @@ static Set get_builtin_menus(const ObjectType object_type, const eO break; case OB_MESH: 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"); @@ -752,7 +852,7 @@ static void catalog_assets_draw(const bContext *C, Menu *menu) if (!active_object) { return; } - asset::AssetItemTree *tree = get_static_item_tree(*C); + asset::AssetItemTree *tree = get_static_item_tree(*active_object); if (!tree) { return; } @@ -822,9 +922,11 @@ MenuType node_group_operator_assets_menu() static bool unassigned_local_poll(const bContext &C) { Main &bmain = *CTX_data_main(&C); - const GeometryNodeAssetTraitFlag flag = asset_flag_for_context( - eContextObjectMode(CTX_data_mode_enum(&C))); - + const Object *active_object = CTX_data_active_object(&C); + if (!active_object) { + return false; + } + const GeometryNodeAssetTraitFlag flag = asset_flag_for_context(*active_object); LISTBASE_FOREACH (const bNodeTree *, group, &bmain.nodetrees) { /* Assets are displayed in other menus, and non-local data-blocks aren't added to this menu. */ if (group->id.library_weak_reference || group->id.asset_data) { @@ -841,7 +943,11 @@ static bool unassigned_local_poll(const bContext &C) static void catalog_assets_draw_unassigned(const bContext *C, Menu *menu) { - asset::AssetItemTree *tree = get_static_item_tree(*C); + const Object *active_object = CTX_data_active_object(C); + if (!active_object) { + return; + } + asset::AssetItemTree *tree = get_static_item_tree(*active_object); if (!tree) { return; } @@ -860,8 +966,7 @@ static void catalog_assets_draw_unassigned(const bContext *C, Menu *menu) asset::operator_asset_reference_props_set(*asset, props_ptr); } - const GeometryNodeAssetTraitFlag flag = asset_flag_for_context( - eContextObjectMode(CTX_data_mode_enum(C))); + const GeometryNodeAssetTraitFlag flag = asset_flag_for_context(*active_object); bool first = true; bool add_separator = !tree->unassigned_assets.is_empty(); @@ -919,7 +1024,11 @@ void ui_template_node_operator_asset_menu_items(uiLayout &layout, const StringRef catalog_path) { bScreen &screen = *CTX_wm_screen(&C); - asset::AssetItemTree *tree = get_static_item_tree(C); + const Object *active_object = CTX_data_active_object(&C); + if (!active_object) { + return; + } + asset::AssetItemTree *tree = get_static_item_tree(*active_object); if (!tree) { return; } @@ -948,12 +1057,12 @@ void ui_template_node_operator_asset_root_items(uiLayout &layout, const bContext if (!active_object) { return; } - asset::AssetItemTree *tree = get_static_item_tree(C); + asset::AssetItemTree *tree = get_static_item_tree(*active_object); if (!tree) { return; } if (tree->assets_per_path.size() == 0) { - *tree = build_catalog_tree(C); + *tree = build_catalog_tree(C, *active_object); } asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available( diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index ee09b4e858d..cafc23093d7 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -931,8 +931,9 @@ typedef enum GeometryNodeAssetTraitFlag { GEO_NODE_ASSET_CURVE = (1 << 4), GEO_NODE_ASSET_POINT_CLOUD = (1 << 5), GEO_NODE_ASSET_MODIFIER = (1 << 6), + GEO_NODE_ASSET_OBJECT = (1 << 7), } GeometryNodeAssetTraitFlag; -ENUM_OPERATORS(GeometryNodeAssetTraitFlag, GEO_NODE_ASSET_MODIFIER); +ENUM_OPERATORS(GeometryNodeAssetTraitFlag, GEO_NODE_ASSET_OBJECT); /* Data structs, for `node->storage`. */ diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index 825c97d6fcc..ff5d32cfd12 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -1802,6 +1802,15 @@ static void rna_GeometryNodeTree_is_modifier_set(PointerRNA *ptr, bool value) geometry_node_asset_trait_flag_set(ptr, GEO_NODE_ASSET_MODIFIER, value); } +static bool rna_GeometryNodeTree_is_mode_object_get(PointerRNA *ptr) +{ + return geometry_node_asset_trait_flag_get(ptr, GEO_NODE_ASSET_OBJECT); +} +static void rna_GeometryNodeTree_is_mode_object_set(PointerRNA *ptr, bool value) +{ + geometry_node_asset_trait_flag_set(ptr, GEO_NODE_ASSET_OBJECT, value); +} + static bool rna_GeometryNodeTree_is_mode_edit_get(PointerRNA *ptr) { return geometry_node_asset_trait_flag_get(ptr, GEO_NODE_ASSET_EDIT); @@ -10272,6 +10281,14 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna) prop, "rna_GeometryNodeTree_is_modifier_get", "rna_GeometryNodeTree_is_modifier_set"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset"); + prop = RNA_def_property(srna, "is_mode_object", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_EDIT); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Edit", "The node group is used in object mode"); + RNA_def_property_boolean_funcs( + prop, "rna_GeometryNodeTree_is_mode_object_get", "rna_GeometryNodeTree_is_mode_object_set"); + RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset"); + prop = RNA_def_property(srna, "is_mode_edit", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_EDIT); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); diff --git a/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh b/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh index 05a08df3c60..2f4b9991853 100644 --- a/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh +++ b/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh @@ -166,6 +166,7 @@ struct GeoNodesModifierData { }; struct GeoNodesOperatorData { + eObjectMode mode; /** The object currently effected by the operator. */ const Object *self_object = nullptr; /** Current evaluated depsgraph. */ 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 420da2f4803..e90c682919d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_tool_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_tool_selection.cc @@ -53,7 +53,12 @@ static void node_geo_exec(GeoNodeExecParams params) if (!check_tool_context_and_error(params)) { return; } - params.set_output("Selection", Field(std::make_shared())); + if (params.user_data()->operator_data->mode == OB_MODE_OBJECT) { + params.set_output("Selection", true); + } + else { + params.set_output("Selection", Field(std::make_shared())); + } } static void node_register() 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 b20ea71dd36..dccc3b0cbb2 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 @@ -37,6 +37,11 @@ static void node_geo_exec(GeoNodeExecParams params) if (!check_tool_context_and_error(params)) { return; } + if (params.user_data()->operator_data->mode == OB_MODE_OBJECT) { + params.error_message_add(NodeWarningType::Error, + "Selection control is not supported in object mode"); + return; + } const Field selection = params.extract_input>("Selection"); const eAttrDomain domain = eAttrDomain(params.node().custom1); GeometrySet geometry = params.extract_input("Geometry");