diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index baa84b550aa..47378dbe468 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -241,6 +241,9 @@ void ED_object_parent(struct Object *ob, struct Object *parent, int type, const char *ED_object_ot_drop_named_material_tooltip(struct bContext *C, const char *name, const int mval[2]); +char *ED_object_ot_drop_geometry_nodes_tooltip(const struct bContext *C, + const struct PointerRNA *properties, + const int mval[2]); /* bitflags for enter/exit editmode */ enum { diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index b136f311557..c58ce0d8424 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -62,6 +62,11 @@ void OBJECT_OT_clear_override_library(struct wmOperatorType *ot); * Assigns to object under cursor, only first material slot. */ void OBJECT_OT_drop_named_material(struct wmOperatorType *ot); +/** + * Used for drop-box. + * Assigns to object under cursor, creates a new geometry nodes modifier. + */ +void OBJECT_OT_drop_geometry_nodes(struct wmOperatorType *ot); /** * \note Only for empty-image objects, this operator is needed */ diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index a73cc98c78e..c8e06ef97c7 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -262,6 +262,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_bake_image); WM_operatortype_append(OBJECT_OT_bake); WM_operatortype_append(OBJECT_OT_drop_named_material); + WM_operatortype_append(OBJECT_OT_drop_geometry_nodes); WM_operatortype_append(OBJECT_OT_unlink_data); WM_operatortype_append(OBJECT_OT_laplaciandeform_bind); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 5315e89c62d..4f76a3b3302 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -99,6 +99,8 @@ #include "ED_screen.h" #include "ED_view3d.h" +#include "MOD_nodes.h" + #include "object_intern.h" /* ------------------------------------------------------------------- */ @@ -2867,6 +2869,119 @@ void OBJECT_OT_drop_named_material(wmOperatorType *ot) /** \} */ +/* ------------------------------------------------------------------- */ +/** \name Drop Geometry Nodes on Object Operator + * \{ */ + +char *ED_object_ot_drop_geometry_nodes_tooltip(const bContext *C, + const PointerRNA *properties, + const int mval[2]) +{ + const Object *ob = ED_view3d_give_object_under_cursor(C, mval); + if (ob == NULL) { + return BLI_strdup(""); + } + + const uint32_t session_uuid = RNA_int_get(properties, "session_uuid"); + const ID *id = BKE_libblock_find_session_uuid(CTX_data_main(C), ID_NT, session_uuid); + if (!id) { + return BLI_strdup(""); + } + + const char *tooltip = TIP_("Add modifier with node group \"%s\" on object \"%s\""); + return BLI_sprintfN(tooltip, id->name, ob->id.name); +} + +static bool check_geometry_node_group_sockets(wmOperator *op, const bNodeTree *tree) +{ + const bNodeSocket *first_input = (const bNodeSocket *)tree->inputs.first; + if (!first_input) { + BKE_report(op->reports, RPT_ERROR, "The node group must have a geometry input socket"); + return false; + } + if (first_input->type != SOCK_GEOMETRY) { + BKE_report(op->reports, RPT_ERROR, "The first input must be a geometry socket"); + return false; + } + const bNodeSocket *first_output = (const bNodeSocket *)tree->outputs.first; + if (!first_output) { + BKE_report(op->reports, RPT_ERROR, "The node group must have a geometry output socket"); + return false; + } + if (first_output->type != SOCK_GEOMETRY) { + BKE_report(op->reports, RPT_ERROR, "The first output must be a geometry socket"); + return false; + } + return true; +} + +static int drop_geometry_nodes_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Object *ob = ED_view3d_give_object_under_cursor(C, event->mval); + if (!ob) { + return OPERATOR_CANCELLED; + } + + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + const uint32_t uuid = RNA_int_get(op->ptr, "session_uuid"); + bNodeTree *node_tree = (bNodeTree *)BKE_libblock_find_session_uuid(bmain, ID_NT, uuid); + if (!node_tree) { + return OPERATOR_CANCELLED; + } + if (node_tree->type != NTREE_GEOMETRY) { + BKE_report(op->reports, RPT_ERROR, "Node group must be a geometry node tree"); + return OPERATOR_CANCELLED; + } + + if (!check_geometry_node_group_sockets(op, node_tree)) { + return OPERATOR_CANCELLED; + } + + NodesModifierData *nmd = (NodesModifierData *)ED_object_modifier_add( + op->reports, bmain, scene, ob, node_tree->id.name + 2, eModifierType_Nodes); + if (!nmd) { + BKE_report(op->reports, RPT_ERROR, "Could not add geometry nodes modifier"); + return OPERATOR_CANCELLED; + } + + nmd->node_group = node_tree; + id_us_plus(&node_tree->id); + MOD_nodes_update_interface(ob, nmd); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, NULL); + + return OPERATOR_FINISHED; +} + +/** \} */ + +void OBJECT_OT_drop_geometry_nodes(wmOperatorType *ot) +{ + ot->name = "Drop Geometry Node Group on Object"; + ot->idname = "OBJECT_OT_drop_geometry_nodes"; + + ot->invoke = drop_geometry_nodes_invoke; + ot->poll = ED_operator_view3d_active; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + + PropertyRNA *prop = RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the geometry node group being dropped", + INT32_MIN, + INT32_MAX); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE)); +} + +/** \} */ + /* ------------------------------------------------------------------- */ /** \name Unlink Object Operator * \{ */ diff --git a/source/blender/editors/space_view3d/space_view3d.cc b/source/blender/editors/space_view3d/space_view3d.cc index 85f650195ed..cd7794300f6 100644 --- a/source/blender/editors/space_view3d/space_view3d.cc +++ b/source/blender/editors/space_view3d/space_view3d.cc @@ -37,6 +37,7 @@ #include "BKE_idprop.h" #include "BKE_lattice.h" #include "BKE_layer.h" +#include "BKE_lib_id.h" #include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_mball.h" @@ -702,6 +703,52 @@ static bool view3d_volume_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEven return (drag->type == WM_DRAG_PATH) && (drag->icon == ICON_FILE_VOLUME); } +static bool view3d_geometry_nodes_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) +{ + if (!view3d_drop_id_in_main_region_poll(C, drag, event, ID_NT)) { + return false; + } + + if (drag->type == WM_DRAG_ID) { + const bNodeTree *node_tree = reinterpret_cast( + WM_drag_get_local_ID(drag, ID_NT)); + if (!node_tree) { + return false; + } + return node_tree->type == NTREE_GEOMETRY; + } + + if (drag->type == WM_DRAG_ASSET) { + const wmDragAsset *asset_data = WM_drag_get_asset_data(drag, ID_NT); + if (!asset_data) { + return false; + } + const IDProperty *tree_type = BKE_asset_metadata_idprop_find(asset_data->metadata, "type"); + if (!tree_type || IDP_Int(tree_type) != NTREE_GEOMETRY) { + return false; + } + if (wmDropBox *drop_box = drag->drop_state.active_dropbox) { + const uint32_t uuid = RNA_int_get(drop_box->ptr, "session_uuid"); + const bNodeTree *node_tree = reinterpret_cast( + BKE_libblock_find_session_uuid(CTX_data_main(C), ID_NT, uuid)); + if (node_tree) { + return node_tree->type == NTREE_GEOMETRY; + } + } + } + return true; +} + +static char *view3d_geometry_nodes_drop_tooltip(bContext *C, + wmDrag * /*drag*/, + const int xy[2], + struct wmDropBox *drop) +{ + ARegion *region = CTX_wm_region(C); + int mval[2] = {xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin}; + return ED_object_ot_drop_geometry_nodes_tooltip(C, drop->ptr, mval); +} + static void view3d_ob_drop_matrix_from_snap(V3DSnapCursorState *snap_state, Object *ob, float obmat_final[4][4]) @@ -930,6 +977,12 @@ static void view3d_dropboxes() view3d_id_drop_copy, WM_drag_free_imported_drag_ID, view3d_mat_drop_tooltip); + WM_dropbox_add(lb, + "OBJECT_OT_drop_geometry_nodes", + view3d_geometry_nodes_drop_poll, + view3d_id_drop_copy, + WM_drag_free_imported_drag_ID, + view3d_geometry_nodes_drop_tooltip); WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll,