diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2021-07-18 14:14:23 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2021-07-18 14:14:23 +0300 |
commit | ca50a1f762703d477ee84cf494dec601fd540299 (patch) | |
tree | fbd86a77e77015d7cc6becc1255a63e436a45b2a /source/blender/editors/space_node | |
parent | d35969a74ff7a71fc0ca233ae65a2f1c47eb9a25 (diff) | |
parent | e82c5c660778b3805f50f3f2901923692c17db2a (diff) |
Merge branch 'master' into geometry-nodes-unnamed-attributesgeometry-nodes-unnamed-attributes
Diffstat (limited to 'source/blender/editors/space_node')
-rw-r--r-- | source/blender/editors/space_node/CMakeLists.txt | 18 | ||||
-rw-r--r-- | source/blender/editors/space_node/drawnode.cc | 36 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_add.cc | 4 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_buttons.c | 223 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_draw.cc | 281 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_edit.cc | 151 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_geometry_attribute_search.cc | 88 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_gizmo.c | 6 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_intern.h | 11 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_ops.c | 3 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_relationships.cc | 50 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_select.cc | 15 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_templates.cc | 2 | ||||
-rw-r--r-- | source/blender/editors/space_node/space_node.c | 10 |
14 files changed, 542 insertions, 356 deletions
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 6e234c5b2ce..80d3b43bf6b 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../compositor ../../depsgraph ../../draw + ../../functions ../../gpu ../../imbuf ../../makesdna @@ -39,7 +40,6 @@ set(INC set(SRC drawnode.cc node_add.cc - node_buttons.c node_draw.cc node_edit.cc node_geometry_attribute_search.cc @@ -78,4 +78,20 @@ if(WITH_OPENSUBDIV) add_definitions(-DWITH_OPENSUBDIV) endif() +if(WITH_TBB) + add_definitions(-DWITH_TBB) + if(WIN32) + # TBB includes Windows.h which will define min/max macros + # that will collide with the stl versions. + add_definitions(-DNOMINMAX) + endif() + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) + + list(APPEND LIB + ${TBB_LIBRARIES} + ) +endif() + blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index d99433b47a8..8da67bbd21b 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -758,7 +758,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA uiItemR(layout, ptr, "extension", DEFAULT_FLAGS, "", ICON_NONE); - /* note: image user properties used directly here, unlike compositor image node, + /* NOTE: image user properties used directly here, unlike compositor image node, * which redefines them in the node struct RNA to get proper updates. */ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false, true); @@ -1953,8 +1953,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi 0, 0, 0, - false, - false); + UI_TEMPLATE_LIST_FLAG_NONE); RNA_property_collection_lookup_int( ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr); } @@ -1972,8 +1971,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi 0, 0, 0, - false, - false); + UI_TEMPLATE_LIST_FLAG_NONE); RNA_property_collection_lookup_int( ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr); } @@ -4029,8 +4027,10 @@ static struct { GPUVertBuf *inst_vbo; uint p0_id, p1_id, p2_id, p3_id; uint colid_id, muted_id; + uint dim_factor_id; GPUVertBufRaw p0_step, p1_step, p2_step, p3_step; GPUVertBufRaw colid_step, muted_step; + GPUVertBufRaw dim_factor_step; uint count; bool enabled; } g_batch_link; @@ -4045,6 +4045,8 @@ static void nodelink_batch_reset() g_batch_link.inst_vbo, g_batch_link.colid_id, &g_batch_link.colid_step); GPU_vertbuf_attr_get_raw_data( g_batch_link.inst_vbo, g_batch_link.muted_id, &g_batch_link.muted_step); + GPU_vertbuf_attr_get_raw_data( + g_batch_link.inst_vbo, g_batch_link.dim_factor_id, &g_batch_link.dim_factor_step); g_batch_link.count = 0; } @@ -4162,6 +4164,8 @@ static void nodelink_batch_init() &format_inst, "colid_doarrow", GPU_COMP_U8, 4, GPU_FETCH_INT); g_batch_link.muted_id = GPU_vertformat_attr_add( &format_inst, "domuted", GPU_COMP_U8, 2, GPU_FETCH_INT); + g_batch_link.dim_factor_id = GPU_vertformat_attr_add( + &format_inst, "dim_factor", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); g_batch_link.inst_vbo = GPU_vertbuf_create_with_format_ex(&format_inst, GPU_USAGE_STREAM); /* Alloc max count but only draw the range we need. */ GPU_vertbuf_data_alloc(g_batch_link.inst_vbo, NODELINK_GROUP_SIZE); @@ -4237,7 +4241,8 @@ static void nodelink_batch_add_link(const SpaceNode *snode, int th_col2, int th_col3, bool drawarrow, - bool drawmuted) + bool drawmuted, + float dim_factor) { /* Only allow these colors. If more is needed, you need to modify the shader accordingly. */ BLI_assert(ELEM(th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT)); @@ -4256,6 +4261,7 @@ static void nodelink_batch_add_link(const SpaceNode *snode, colid[3] = drawarrow; char *muted = (char *)GPU_vertbuf_raw_step(&g_batch_link.muted_step); muted[0] = drawmuted; + *(float *)GPU_vertbuf_raw_step(&g_batch_link.dim_factor_step) = dim_factor; if (g_batch_link.count == NODELINK_GROUP_SIZE) { nodelink_batch_draw(snode); @@ -4270,6 +4276,8 @@ void node_draw_link_bezier(const View2D *v2d, int th_col2, int th_col3) { + const float dim_factor = node_link_dim_factor(v2d, link); + float vec[4][2]; const bool highlighted = link->flag & NODE_LINK_TEMP_HIGHLIGHT; if (node_link_bezier_handles(v2d, snode, link, vec)) { @@ -4282,8 +4290,17 @@ void node_draw_link_bezier(const View2D *v2d, if (g_batch_link.enabled && !highlighted) { /* Add link to batch. */ - nodelink_batch_add_link( - snode, vec[0], vec[1], vec[2], vec[3], th_col1, th_col2, th_col3, drawarrow, drawmuted); + nodelink_batch_add_link(snode, + vec[0], + vec[1], + vec[2], + vec[3], + th_col1, + th_col2, + th_col3, + drawarrow, + drawmuted, + dim_factor); } else { /* Draw single link. */ @@ -4308,12 +4325,13 @@ void node_draw_link_bezier(const View2D *v2d, GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE); GPU_batch_uniform_1i(batch, "doArrow", drawarrow); GPU_batch_uniform_1i(batch, "doMuted", drawmuted); + GPU_batch_uniform_1f(batch, "dim_factor", dim_factor); GPU_batch_draw(batch); } } } -/* note; this is used for fake links in groups too */ +/* NOTE: this is used for fake links in groups too. */ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link) { int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE; diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index 6143af8ed70..9264c9d3572 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -90,7 +90,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx nodeSetSelected(node, true); ntreeUpdateTree(bmain, snode->edittree); - ED_node_set_active(bmain, snode->edittree, node, nullptr); + ED_node_set_active(bmain, snode, snode->edittree, node, nullptr); snode_update(snode, node); @@ -260,7 +260,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op) BLI_listbase_clear(&input_links); for (link = (bNodeLink *)ntree->links.first; link; link = link->next) { - if (nodeLinkIsHidden(link)) { + if (node_link_is_hidden_or_dimmed(®ion->v2d, link)) { continue; } if (add_reroute_intersect_check(link, mcoords, i, insert_point)) { diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c deleted file mode 100644 index 336b0c46a81..00000000000 --- a/source/blender/editors/space_node/node_buttons.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2009 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup spnode - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_node_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" - -#include "BLT_translation.h" - -#include "BKE_context.h" -#include "BKE_global.h" -#include "BKE_node.h" -#include "BKE_screen.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "RNA_access.h" - -#include "ED_screen.h" - -#include "UI_resources.h" - -#include "node_intern.h" /* own include */ - -/* ******************* node space & buttons ************** */ - -#if 0 -/* poll for active nodetree */ -static bool active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - return (snode && snode->nodetree); -} -#endif - -static bool node_sockets_poll(const bContext *C, PanelType *UNUSED(pt)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - return (snode && snode->nodetree && G.debug_value == 777); -} - -static void node_sockets_panel(const bContext *C, Panel *panel) -{ - SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */ - bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */ - bNode *node = nodeGetActive(ntree); - if (node == NULL) { - return; - } - - LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { - char name[UI_MAX_NAME_STR]; - BLI_snprintf(name, sizeof(name), "%s:", socket->name); - - uiLayout *split = uiLayoutSplit(panel->layout, 0.35f, false); - uiItemL(split, name, ICON_NONE); - uiTemplateNodeLink(split, (bContext *)C, ntree, node, socket); - } -} - -static bool node_tree_interface_poll(const bContext *C, PanelType *UNUSED(pt)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - return (snode && snode->edittree && - (snode->edittree->inputs.first || snode->edittree->outputs.first)); -} - -static bNodeSocket *node_tree_find_active_socket(bNodeTree *ntree, const eNodeSocketInOut in_out) -{ - ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs; - LISTBASE_FOREACH (bNodeSocket *, socket, sockets) { - if (socket->flag & SELECT) { - return socket; - } - } - return NULL; -} - -static void draw_socket_list(const bContext *C, - uiLayout *layout, - bNodeTree *ntree, - const eNodeSocketInOut in_out) -{ - PointerRNA tree_ptr; - RNA_id_pointer_create((ID *)ntree, &tree_ptr); - - uiLayout *split = uiLayoutRow(layout, false); - uiLayout *list_col = uiLayoutColumn(split, true); - uiTemplateList(list_col, - (bContext *)C, - "NODE_UL_interface_sockets", - (in_out == SOCK_IN) ? "inputs" : "outputs", - &tree_ptr, - (in_out == SOCK_IN) ? "inputs" : "outputs", - &tree_ptr, - (in_out == SOCK_IN) ? "active_input" : "active_output", - NULL, - 0, - 0, - 0, - 0, - false, - false); - PointerRNA opptr; - uiLayout *ops_col = uiLayoutColumn(split, false); - uiLayout *add_remove_col = uiLayoutColumn(ops_col, true); - wmOperatorType *ot = WM_operatortype_find("NODE_OT_tree_socket_add", false); - uiItemFullO_ptr(add_remove_col, ot, "", ICON_ADD, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); - RNA_enum_set(&opptr, "in_out", in_out); - ot = WM_operatortype_find("NODE_OT_tree_socket_remove", false); - uiItemFullO_ptr(add_remove_col, ot, "", ICON_REMOVE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); - RNA_enum_set(&opptr, "in_out", in_out); - - uiItemS(ops_col); - - uiLayout *up_down_col = uiLayoutColumn(ops_col, true); - ot = WM_operatortype_find("NODE_OT_tree_socket_move", false); - uiItemFullO_ptr(up_down_col, ot, "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); - RNA_enum_set(&opptr, "direction", 1); - RNA_enum_set(&opptr, "in_out", in_out); - uiItemFullO_ptr(up_down_col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); - RNA_enum_set(&opptr, "direction", 2); - RNA_enum_set(&opptr, "in_out", in_out); - - bNodeSocket *socket = node_tree_find_active_socket(ntree, in_out); - if (socket != NULL) { - uiLayoutSetPropSep(layout, true); - uiLayoutSetPropDecorate(layout, false); - PointerRNA socket_ptr; - RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, socket, &socket_ptr); - uiItemR(layout, &socket_ptr, "name", 0, NULL, ICON_NONE); - - /* Display descriptions only for Geometry Nodes, since it's only used in the modifier panel. */ - if (ntree->type == NTREE_GEOMETRY) { - uiItemR(layout, &socket_ptr, "description", 0, NULL, ICON_NONE); - } - - if (socket->typeinfo->interface_draw) { - socket->typeinfo->interface_draw((bContext *)C, layout, &socket_ptr); - } - } -} - -static void node_tree_interface_inputs_panel(const bContext *C, Panel *panel) -{ - SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */ - bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */ - - draw_socket_list(C, panel->layout, ntree, SOCK_IN); -} - -static void node_tree_interface_outputs_panel(const bContext *C, Panel *panel) -{ - SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */ - bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */ - - draw_socket_list(C, panel->layout, ntree, SOCK_OUT); -} - -/* ******************* node buttons registration ************** */ - -void node_buttons_register(ARegionType *art) -{ - { - PanelType *pt = MEM_callocN(sizeof(PanelType), __func__); - strcpy(pt->idname, "NODE_PT_sockets"); - strcpy(pt->category, N_("Node")); - strcpy(pt->label, N_("Sockets")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = node_sockets_panel; - pt->poll = node_sockets_poll; - pt->flag |= PANEL_TYPE_DEFAULT_CLOSED; - BLI_addtail(&art->paneltypes, pt); - } - - { - PanelType *pt = MEM_callocN(sizeof(PanelType), __func__); - strcpy(pt->idname, "NODE_PT_node_tree_interface_inputs"); - strcpy(pt->category, N_("Group")); - strcpy(pt->label, N_("Inputs")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = node_tree_interface_inputs_panel; - pt->poll = node_tree_interface_poll; - BLI_addtail(&art->paneltypes, pt); - } - { - PanelType *pt = MEM_callocN(sizeof(PanelType), __func__); - strcpy(pt->idname, "NODE_PT_node_tree_interface_outputs"); - strcpy(pt->category, N_("Group")); - strcpy(pt->label, N_("Outputs")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = node_tree_interface_outputs_panel; - pt->poll = node_tree_interface_poll; - BLI_addtail(&art->paneltypes, pt); - } -} diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 8599b159cca..ed88489c63e 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -45,10 +45,10 @@ #include "BLT_translation.h" #include "BKE_context.h" +#include "BKE_idtype.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" -#include "BKE_node_ui_storage.hh" #include "BKE_object.h" #include "DEG_depsgraph.h" @@ -76,6 +76,8 @@ #include "RNA_access.h" +#include "NOD_geometry_nodes_eval_log.hh" + #include "node_intern.h" /* own include */ #ifdef WITH_COMPOSITOR @@ -86,6 +88,9 @@ using blender::Map; using blender::Set; using blender::Span; using blender::Vector; +using blender::fn::CPPType; +using blender::fn::GPointer; +namespace geo_log = blender::nodes::geometry_nodes_eval_log; extern "C" { /* XXX interface.h */ @@ -833,6 +838,149 @@ void node_socket_color_get(bContext *C, } } +struct SocketTooltipData { + bNodeTree *ntree; + bNode *node; + bNodeSocket *socket; +}; + +static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log, + std::stringstream &ss) +{ + auto id_to_inspection_string = [&](ID *id) { + ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(GS(id->name)) + << ")"; + }; + + const GPointer value = value_log.value(); + if (value.is_type<int>()) { + ss << *value.get<int>() << TIP_(" (Integer)"); + } + else if (value.is_type<float>()) { + ss << *value.get<float>() << TIP_(" (Float)"); + } + else if (value.is_type<blender::float3>()) { + ss << *value.get<blender::float3>() << TIP_(" (Vector)"); + } + else if (value.is_type<bool>()) { + ss << (*value.get<bool>() ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)"); + } + else if (value.is_type<std::string>()) { + ss << *value.get<std::string>() << TIP_(" (String)"); + } + else if (value.is_type<Object *>()) { + id_to_inspection_string((ID *)*value.get<Object *>()); + } + else if (value.is_type<Material *>()) { + id_to_inspection_string((ID *)*value.get<Material *>()); + } + else if (value.is_type<Tex *>()) { + id_to_inspection_string((ID *)*value.get<Tex *>()); + } + else if (value.is_type<Collection *>()) { + id_to_inspection_string((ID *)*value.get<Collection *>()); + } +} + +static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log, + std::stringstream &ss) +{ + Span<GeometryComponentType> component_types = value_log.component_types(); + if (component_types.is_empty()) { + ss << TIP_("Empty Geometry"); + return; + } + + auto to_string = [](int value) { + char str[16]; + BLI_str_format_int_grouped(str, value); + return std::string(str); + }; + + ss << TIP_("Geometry:\n"); + for (GeometryComponentType type : component_types) { + const char *line_end = (type == component_types.last()) ? "" : ".\n"; + switch (type) { + case GEO_COMPONENT_TYPE_MESH: { + const geo_log::GeometryValueLog::MeshInfo &mesh_info = *value_log.mesh_info; + char line[256]; + BLI_snprintf(line, + sizeof(line), + TIP_("\u2022 Mesh: %s vertices, %s edges, %s faces"), + to_string(mesh_info.tot_verts).c_str(), + to_string(mesh_info.tot_edges).c_str(), + to_string(mesh_info.tot_faces).c_str()); + ss << line << line_end; + break; + } + case GEO_COMPONENT_TYPE_POINT_CLOUD: { + const geo_log::GeometryValueLog::PointCloudInfo &pointcloud_info = + *value_log.pointcloud_info; + char line[256]; + BLI_snprintf(line, + sizeof(line), + TIP_("\u2022 Point Cloud: %s points"), + to_string(pointcloud_info.tot_points).c_str()); + ss << line << line_end; + break; + } + case GEO_COMPONENT_TYPE_CURVE: { + const geo_log::GeometryValueLog::CurveInfo &curve_info = *value_log.curve_info; + char line[256]; + BLI_snprintf(line, + sizeof(line), + TIP_("\u2022 Curve: %s splines"), + to_string(curve_info.tot_splines).c_str()); + ss << line << line_end; + break; + } + case GEO_COMPONENT_TYPE_INSTANCES: { + const geo_log::GeometryValueLog::InstancesInfo &instances_info = *value_log.instances_info; + char line[256]; + BLI_snprintf(line, + sizeof(line), + TIP_("\u2022 Instances: %s"), + to_string(instances_info.tot_instances).c_str()); + ss << line << line_end; + break; + } + case GEO_COMPONENT_TYPE_VOLUME: { + ss << TIP_("\u2022 Volume") << line_end; + break; + } + } + } +} + +static std::optional<std::string> create_socket_inspection_string(bContext *C, + bNodeTree &UNUSED(ntree), + bNode &node, + bNodeSocket &socket) +{ + SpaceNode *snode = CTX_wm_space_node(C); + const geo_log::SocketLog *socket_log = geo_log::ModifierLog::find_socket_by_node_editor_context( + *snode, node, socket); + if (socket_log == nullptr) { + return {}; + } + const geo_log::ValueLog *value_log = socket_log->value(); + if (value_log == nullptr) { + return {}; + } + + std::stringstream ss; + if (const geo_log::GenericValueLog *generic_value_log = + dynamic_cast<const geo_log::GenericValueLog *>(value_log)) { + create_inspection_string_for_generic_value(*generic_value_log, ss); + } + else if (const geo_log::GeometryValueLog *geo_value_log = + dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) { + create_inspection_string_for_geometry(*geo_value_log, ss); + } + + return ss.str(); +} + static void node_socket_draw_nested(const bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, @@ -863,6 +1011,55 @@ static void node_socket_draw_nested(const bContext *C, shape_id, size_id, outline_col_id); + + if (ntree->type != NTREE_GEOMETRY) { + /* Only geometry nodes has socket value tooltips currently. */ + return; + } + + bNode *node = (bNode *)node_ptr->data; + uiBlock *block = node->block; + + /* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible + * button on top of them for the tooltip. */ + const eUIEmbossType old_emboss = UI_block_emboss_get(block); + UI_block_emboss_set(block, UI_EMBOSS_NONE); + uiBut *but = uiDefIconBut(block, + UI_BTYPE_BUT, + 0, + ICON_NONE, + sock->locx - size / 2, + sock->locy - size / 2, + size, + size, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + + SocketTooltipData *data = (SocketTooltipData *)MEM_mallocN(sizeof(SocketTooltipData), __func__); + data->ntree = ntree; + data->node = (bNode *)node_ptr->data; + data->socket = sock; + + UI_but_func_tooltip_set( + but, + [](bContext *C, void *argN, const char *UNUSED(tip)) { + SocketTooltipData *data = (SocketTooltipData *)argN; + std::optional<std::string> str = create_socket_inspection_string( + C, *data->ntree, *data->node, *data->socket); + if (str.has_value()) { + return BLI_strdup(str->c_str()); + } + return BLI_strdup(TIP_("The socket value has not been computed yet")); + }, + data, + MEM_freeN); + /* Disable the button so that clicks on it are ignored the the link operator still works. */ + UI_but_flag_enable(but, UI_BUT_DISABLED); + UI_block_emboss_set(block, old_emboss); } /** @@ -1203,14 +1400,14 @@ void node_draw_sockets(const View2D *v2d, } } -static int node_error_type_to_icon(const NodeWarningType type) +static int node_error_type_to_icon(const geo_log::NodeWarningType type) { switch (type) { - case NodeWarningType::Error: + case geo_log::NodeWarningType::Error: return ICON_ERROR; - case NodeWarningType::Warning: + case geo_log::NodeWarningType::Warning: return ICON_ERROR; - case NodeWarningType::Info: + case geo_log::NodeWarningType::Info: return ICON_INFO; } @@ -1218,14 +1415,14 @@ static int node_error_type_to_icon(const NodeWarningType type) return ICON_ERROR; } -static uint8_t node_error_type_priority(const NodeWarningType type) +static uint8_t node_error_type_priority(const geo_log::NodeWarningType type) { switch (type) { - case NodeWarningType::Error: + case geo_log::NodeWarningType::Error: return 3; - case NodeWarningType::Warning: + case geo_log::NodeWarningType::Warning: return 2; - case NodeWarningType::Info: + case geo_log::NodeWarningType::Info: return 1; } @@ -1233,11 +1430,11 @@ static uint8_t node_error_type_priority(const NodeWarningType type) return 0; } -static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings) +static geo_log::NodeWarningType node_error_highest_priority(Span<geo_log::NodeWarning> warnings) { uint8_t highest_priority = 0; - NodeWarningType highest_priority_type = NodeWarningType::Info; - for (const NodeWarning &warning : warnings) { + geo_log::NodeWarningType highest_priority_type = geo_log::NodeWarningType::Info; + for (const geo_log::NodeWarning &warning : warnings) { const uint8_t priority = node_error_type_priority(warning.type); if (priority > highest_priority) { highest_priority = priority; @@ -1247,15 +1444,17 @@ static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings) return highest_priority_type; } +struct NodeErrorsTooltipData { + Span<geo_log::NodeWarning> warnings; +}; + static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char *UNUSED(tip)) { - const NodeUIStorage **storage_pointer_alloc = static_cast<const NodeUIStorage **>(argN); - const NodeUIStorage *node_ui_storage = *storage_pointer_alloc; - Span<NodeWarning> warnings = node_ui_storage->warnings; + NodeErrorsTooltipData &data = *(NodeErrorsTooltipData *)argN; std::string complete_string; - for (const NodeWarning &warning : warnings.drop_back(1)) { + for (const geo_log::NodeWarning &warning : data.warnings.drop_back(1)) { complete_string += warning.message; /* Adding the period is not ideal for multi-line messages, but it is consistent * with other tooltip implementations in Blender, so it is added here. */ @@ -1264,7 +1463,7 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char } /* Let the tooltip system automatically add the last period. */ - complete_string += warnings.last().message; + complete_string += data.warnings.last().message; return BLI_strdupn(complete_string.c_str(), complete_string.size()); } @@ -1272,20 +1471,26 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char #define NODE_HEADER_ICON_SIZE (0.8f * U.widget_unit) static void node_add_error_message_button( - const bContext *C, bNodeTree &ntree, bNode &node, const rctf &rect, float &icon_offset) + const bContext *C, bNodeTree &UNUSED(ntree), bNode &node, const rctf &rect, float &icon_offset) { - const NodeUIStorage *node_ui_storage = BKE_node_tree_ui_storage_get_from_context(C, ntree, node); - if (node_ui_storage == nullptr || node_ui_storage->warnings.is_empty()) { + SpaceNode *snode = CTX_wm_space_node(C); + const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(*snode, + node); + if (node_log == nullptr) { + return; + } + + Span<geo_log::NodeWarning> warnings = node_log->warnings(); + + if (warnings.is_empty()) { return; } - /* The UI API forces us to allocate memory for each error button, because the - * ownership of #UI_but_func_tooltip_set's argument is transferred to the button. */ - const NodeUIStorage **storage_pointer_alloc = (const NodeUIStorage **)MEM_mallocN( - sizeof(NodeUIStorage *), __func__); - *storage_pointer_alloc = node_ui_storage; + NodeErrorsTooltipData *tooltip_data = (NodeErrorsTooltipData *)MEM_mallocN( + sizeof(NodeErrorsTooltipData), __func__); + tooltip_data->warnings = warnings; - const NodeWarningType display_type = node_error_highest_priority(node_ui_storage->warnings); + const geo_log::NodeWarningType display_type = node_error_highest_priority(warnings); icon_offset -= NODE_HEADER_ICON_SIZE; UI_block_emboss_set(node.block, UI_EMBOSS_NONE); @@ -1303,7 +1508,7 @@ static void node_add_error_message_button( 0, 0, nullptr); - UI_but_func_tooltip_set(but, node_errors_tooltip_fn, storage_pointer_alloc, MEM_freeN); + UI_but_func_tooltip_set(but, node_errors_tooltip_fn, tooltip_data, MEM_freeN); UI_block_emboss_set(node.block, UI_EMBOSS); } @@ -1423,28 +1628,6 @@ static void node_draw_basis(const bContext *C, ""); UI_block_emboss_set(node->block, UI_EMBOSS); } - if (ntree->type == NTREE_GEOMETRY) { - /* Active preview toggle. */ - iconofs -= iconbutw; - UI_block_emboss_set(node->block, UI_EMBOSS_NONE); - int icon = (node->flag & NODE_ACTIVE_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON; - uiBut *but = uiDefIconBut(node->block, - UI_BTYPE_BUT_TOGGLE, - 0, - icon, - iconofs, - rct->ymax - NODE_DY, - iconbutw, - UI_UNIT_Y, - nullptr, - 0, - 0, - 0, - 0, - "Show this node's geometry output in the spreadsheet"); - UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_active_preview_toggle"); - UI_block_emboss_set(node->block, UI_EMBOSS); - } node_add_error_message_button(C, *ntree, *node, *rct, iconofs); diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 0cf47ed35fa..af9c888cbf7 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -21,6 +21,8 @@ * \ingroup spnode */ +#include <algorithm> + #include "MEM_guardedalloc.h" #include "DNA_light_types.h" @@ -54,6 +56,7 @@ #include "ED_render.h" #include "ED_screen.h" #include "ED_select_utils.h" +#include "ED_spreadsheet.h" #include "RNA_access.h" #include "RNA_define.h" @@ -662,7 +665,8 @@ void snode_update(SpaceNode *snode, bNode *node) } } -void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed) +void ED_node_set_active( + Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed) { const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0; if (r_active_texture_changed) { @@ -782,6 +786,19 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti } #endif } + else if (ntree->type == NTREE_GEOMETRY) { + if (node->type == GEO_NODE_VIEWER) { + if ((node->flag & NODE_DO_OUTPUT) == 0) { + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (node_iter->type == GEO_NODE_VIEWER) { + node_iter->flag &= ~NODE_DO_OUTPUT; + } + } + node->flag |= NODE_DO_OUTPUT; + ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, node); + } + } + } } } @@ -1211,6 +1228,32 @@ int node_find_indicated_socket( return 0; } +/* ****************** Link Dimming *********************** */ + +float node_link_dim_factor(const View2D *v2d, const bNodeLink *link) +{ + if (link->fromsock == nullptr || link->tosock == nullptr) { + return 1.0f; + } + + const float min_endpoint_distance = std::min( + std::max(BLI_rctf_length_x(&v2d->cur, link->fromsock->locx), + BLI_rctf_length_y(&v2d->cur, link->fromsock->locy)), + std::max(BLI_rctf_length_x(&v2d->cur, link->tosock->locx), + BLI_rctf_length_y(&v2d->cur, link->tosock->locy))); + + if (min_endpoint_distance == 0.0f) { + return 1.0f; + } + const float viewport_width = BLI_rctf_size_x(&v2d->cur); + return std::clamp(1.0f - min_endpoint_distance / viewport_width * 10.0f, 0.05f, 1.0f); +} + +bool node_link_is_hidden_or_dimmed(const View2D *v2d, const bNodeLink *link) +{ + return nodeLinkIsHidden(link) || node_link_dim_factor(v2d, link) < 0.5f; +} + /* ****************** Duplicate *********************** */ static void node_duplicate_reparent_recursive(bNode *node) @@ -1318,7 +1361,6 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) nodeSetSelected(node, false); node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE); nodeSetSelected(newnode, true); - newnode->flag &= ~NODE_ACTIVE_PREVIEW; do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode)); } @@ -2313,7 +2355,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op) // nodeSocketCopyValue(sock, &ntree_ptr, active_sock, &ntree_ptr); } else { - /* XXX TODO define default socket type for a tree! */ + /* XXX TODO: define default socket type for a tree! */ sock = ntreeAddSocketInterface(ntree, in_out, "NodeSocketFloat", default_name); } @@ -2400,6 +2442,109 @@ void NODE_OT_tree_socket_remove(wmOperatorType *ot) RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", ""); } +/********************** Change interface socket type operator *********************/ + +static int ntree_socket_change_type_exec(bContext *C, wmOperator *op) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + const eNodeSocketInOut in_out = (eNodeSocketInOut)RNA_enum_get(op->ptr, "in_out"); + const bNodeSocketType *socket_type = rna_node_socket_type_from_enum( + RNA_enum_get(op->ptr, "socket_type")); + ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs; + + Main *main = CTX_data_main(C); + + bNodeSocket *iosock = ntree_get_active_interface_socket(sockets); + if (iosock == nullptr) { + return OPERATOR_CANCELLED; + } + + /* The type remains the same, so we don't need to change anything. */ + if (iosock->typeinfo == socket_type) { + return OPERATOR_FINISHED; + } + + /* Don't handle subtypes for now. */ + nodeModifySocketType(ntree, nullptr, iosock, socket_type->idname); + + /* Need the extra update here because the loop above does not check for valid links in the node + * group we're currently editing. */ + ntree->update |= NTREE_UPDATE_GROUP | NTREE_UPDATE_LINKS; + + /* Deactivate sockets. */ + LISTBASE_FOREACH (bNodeSocket *, socket_iter, sockets) { + socket_iter->flag &= ~SELECT; + } + /* Make the new socket active. */ + iosock->flag |= SELECT; + + ntreeUpdateTree(main, ntree); + + snode_notify(C, snode); + snode_dag_update(C, snode); + + WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); + + return OPERATOR_FINISHED; +} + +static bool socket_change_poll_type(void *userdata, bNodeSocketType *socket_type) +{ + /* Check if the node tree supports the socket type. */ + bNodeTreeType *ntreetype = (bNodeTreeType *)userdata; + if (ntreetype->valid_socket_type && !ntreetype->valid_socket_type(ntreetype, socket_type)) { + return false; + } + + /* Only use basic socket types for this enum. */ + if (socket_type->subtype != PROP_NONE) { + return false; + } + + return true; +} + +static const EnumPropertyItem *socket_change_type_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + if (!C) { + return DummyRNA_NULL_items; + } + + SpaceNode *snode = CTX_wm_space_node(C); + if (!snode || !snode->edittree) { + return DummyRNA_NULL_items; + } + + return rna_node_socket_type_itemf(snode->edittree->typeinfo, socket_change_poll_type, r_free); +} + +void NODE_OT_tree_socket_change_type(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Change Node Tree Interface Socket Type"; + ot->description = "Change the type of a socket of the current node tree"; + ot->idname = "NODE_OT_tree_socket_change_type"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = ntree_socket_change_type_exec; + ot->poll = ED_operator_node_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", ""); + prop = RNA_def_enum(ot->srna, "socket_type", DummyRNA_DEFAULT_items, 0, "Socket Type", ""); + RNA_def_enum_funcs(prop, socket_change_type_itemf); + ot->prop = prop; +} + /********************** Move interface socket operator *********************/ static const EnumPropertyItem move_direction_items[] = { diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index e92449e3535..af35f9692ae 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -27,7 +27,6 @@ #include "DNA_space_types.h" #include "BKE_context.h" -#include "BKE_node_ui_storage.hh" #include "BKE_object.h" #include "RNA_access.h" @@ -40,17 +39,21 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "NOD_geometry_nodes_eval_log.hh" + #include "node_intern.h" using blender::IndexRange; using blender::Map; using blender::Set; using blender::StringRef; +namespace geo_log = blender::nodes::geometry_nodes_eval_log; +using geo_log::GeometryAttributeInfo; struct AttributeSearchData { - AvailableAttributeInfo &dummy_info_for_search; - const NodeUIStorage &ui_storage; - bNodeSocket &socket; + const bNodeTree *tree; + const bNode *node; + bNodeSocket *socket; }; /* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */ @@ -73,7 +76,7 @@ static StringRef attribute_domain_string(const AttributeDomain domain) /* Unicode arrow. */ #define MENU_SEP "\xe2\x96\xb6" -static bool attribute_search_item_add(uiSearchItems *items, const AvailableAttributeInfo &item) +static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttributeInfo &item) { const StringRef data_type_name = attribute_data_type_string(item.data_type); const StringRef domain_name = attribute_domain_string(item.domain); @@ -84,31 +87,47 @@ static bool attribute_search_item_add(uiSearchItems *items, const AvailableAttri items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0); } -static void attribute_search_update_fn(const bContext *UNUSED(C), - void *arg, - const char *str, - uiSearchItems *items, - const bool is_first) +static GeometryAttributeInfo &get_dummy_item_info() +{ + static GeometryAttributeInfo info; + return info; +} + +static void attribute_search_update_fn( + const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first) { AttributeSearchData *data = static_cast<AttributeSearchData *>(arg); - const Set<AvailableAttributeInfo> &attribute_hints = data->ui_storage.attribute_hints; + SpaceNode *snode = CTX_wm_space_node(C); + const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context( + *snode, *data->node); + if (node_log == nullptr) { + return; + } + blender::Vector<const GeometryAttributeInfo *> infos = node_log->lookup_available_attributes(); + + GeometryAttributeInfo &dummy_info = get_dummy_item_info(); /* Any string may be valid, so add the current search string along with the hints. */ if (str[0] != '\0') { - /* Note that the attribute domain and data type are dummies, since - * #AvailableAttributeInfo equality is only based on the string. */ - if (!attribute_hints.contains(AvailableAttributeInfo{str, ATTR_DOMAIN_AUTO, CD_PROP_BOOL})) { - data->dummy_info_for_search.name = std::string(str); - UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_ADD, 0, 0); + bool contained = false; + for (const GeometryAttributeInfo *attribute_info : infos) { + if (attribute_info->name == str) { + contained = true; + break; + } + } + if (!contained) { + dummy_info.name = str; + UI_search_item_add(items, str, &dummy_info, ICON_ADD, 0, 0); } } if (str[0] == '\0' && !is_first) { /* Allow clearing the text field when the string is empty, but not on the first pass, * or opening an attribute field for the first time would show this search item. */ - data->dummy_info_for_search.name = std::string(str); - UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_X, 0, 0); + dummy_info.name = str; + UI_search_item_add(items, str, &dummy_info, ICON_X, 0, 0); } /* Don't filter when the menu is first opened, but still run the search @@ -116,15 +135,15 @@ static void attribute_search_update_fn(const bContext *UNUSED(C), const char *string = is_first ? "" : str; StringSearch *search = BLI_string_search_new(); - for (const AvailableAttributeInfo &item : attribute_hints) { - BLI_string_search_add(search, item.name.c_str(), (void *)&item); + for (const GeometryAttributeInfo *item : infos) { + BLI_string_search_add(search, item->name.c_str(), (void *)item); } - AvailableAttributeInfo **filtered_items; + GeometryAttributeInfo **filtered_items; const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items); for (const int i : IndexRange(filtered_amount)) { - const AvailableAttributeInfo *item = filtered_items[i]; + const GeometryAttributeInfo *item = filtered_items[i]; if (!attribute_search_item_add(items, *item)) { break; } @@ -136,10 +155,13 @@ static void attribute_search_update_fn(const bContext *UNUSED(C), static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v) { + if (item_v == nullptr) { + return; + } AttributeSearchData *data = static_cast<AttributeSearchData *>(data_v); - AvailableAttributeInfo *item = static_cast<AvailableAttributeInfo *>(item_v); + GeometryAttributeInfo *item = (GeometryAttributeInfo *)item_v; - bNodeSocket &socket = data->socket; + bNodeSocket &socket = *data->socket; switch (socket.type) { case SOCK_STRING: { bNodeSocketValueString *value = static_cast<bNodeSocketValueString *>(socket.default_value); @@ -157,23 +179,13 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v) ED_undo_push(C, "Assign Attribute Name"); } -void node_geometry_add_attribute_search_button(const bContext *C, +void node_geometry_add_attribute_search_button(const bContext *UNUSED(C), const bNodeTree *node_tree, const bNode *node, PointerRNA *socket_ptr, const char *propname, uiLayout *layout) { - const NodeUIStorage *ui_storage = BKE_node_tree_ui_storage_get_from_context( - C, *node_tree, *node); - - if (ui_storage == nullptr) { - uiItemR(layout, socket_ptr, propname, 0, "", 0); - return; - } - - const NodeTreeUIStorage *tree_ui_storage = node_tree->ui_storage; - uiBlock *block = uiLayoutGetBlock(layout); uiBut *but = uiDefIconTextButR(block, UI_BTYPE_SEARCH_MENU, @@ -193,10 +205,8 @@ void node_geometry_add_attribute_search_button(const bContext *C, 0.0f, ""); - AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData, - {tree_ui_storage->dummy_info_for_search, - *ui_storage, - *static_cast<bNodeSocket *>(socket_ptr->data)}); + AttributeSearchData *data = OBJECT_GUARDED_NEW( + AttributeSearchData, {node_tree, node, (bNodeSocket *)socket_ptr->data}); UI_but_func_search_set_results_are_suggestions(but, true); UI_but_func_search_set_sep_string(but, MENU_SEP); diff --git a/source/blender/editors/space_node/node_gizmo.c b/source/blender/editors/space_node/node_gizmo.c index 8547c825230..e1deca54890 100644 --- a/source/blender/editors/space_node/node_gizmo.c +++ b/source/blender/editors/space_node/node_gizmo.c @@ -155,7 +155,7 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup * WM_gizmo_set_matrix_location(cage, origin); WM_gizmo_set_flag(cage, WM_GIZMO_HIDDEN, false); - /* need to set property here for undo. TODO would prefer to do this in _init */ + /* Need to set property here for undo. TODO: would prefer to do this in _init. */ SpaceNode *snode = CTX_wm_space_node(C); #if 0 PointerRNA nodeptr; @@ -492,7 +492,7 @@ static void WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmGizmoGroup *gzgr SpaceNode *snode = CTX_wm_space_node(C); bNode *node = nodeGetActive(snode->edittree); - /* need to set property here for undo. TODO would prefer to do this in _init */ + /* Need to set property here for undo. TODO: would prefer to do this in _init. */ PointerRNA nodeptr; RNA_pointer_create((ID *)snode->edittree, &RNA_CompositorNodeSunBeams, node, &nodeptr); WM_gizmo_target_property_def_rna(gz, "offset", &nodeptr, "source", -1); @@ -604,7 +604,7 @@ static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup SpaceNode *snode = CTX_wm_space_node(C); bNode *node = nodeGetActive(snode->edittree); - /* need to set property here for undo. TODO would prefer to do this in _init */ + /* need to set property here for undo. TODO: would prefer to do this in _init. */ int i = 0; for (bNodeSocket *sock = node->inputs.first; sock && i < 4; sock = sock->next) { if (sock->type == SOCK_VECTOR) { diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 73de87b8c14..385bf8ab4a8 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -52,7 +52,7 @@ typedef struct bNodeLinkDrag { struct bNodeLinkDrag *next, *prev; /* List of links dragged by the operator. - * Note: This is a list of LinkData structs on top of the actual bNodeLinks. + * NOTE: This is a list of LinkData structs on top of the actual bNodeLinks. * This way the links can be added to the node tree while being stored in this list. */ ListBase links; @@ -141,9 +141,6 @@ void node_to_view(const struct bNode *node, float x, float y, float *rx, float * void node_to_updated_rect(const struct bNode *node, rctf *r_rect); void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry); -/* node_buttons.c */ -void node_buttons_register(struct ARegionType *art); - /* node_toolbar.c */ void node_toolbar_register(struct ARegionType *art); @@ -269,6 +266,8 @@ int node_find_indicated_socket(struct SpaceNode *snode, struct bNodeSocket **sockp, const float cursor[2], int in_out); +float node_link_dim_factor(const struct View2D *v2d, const struct bNodeLink *link); +bool node_link_is_hidden_or_dimmed(const struct View2D *v2d, const struct bNodeLink *link); void NODE_OT_duplicate(struct wmOperatorType *ot); void NODE_OT_delete(struct wmOperatorType *ot); @@ -280,7 +279,6 @@ void NODE_OT_hide_toggle(struct wmOperatorType *ot); void NODE_OT_hide_socket_toggle(struct wmOperatorType *ot); void NODE_OT_preview_toggle(struct wmOperatorType *ot); void NODE_OT_options_toggle(struct wmOperatorType *ot); -void NODE_OT_active_preview_toggle(struct wmOperatorType *ot); void NODE_OT_node_copy_color(struct wmOperatorType *ot); void NODE_OT_read_viewlayers(struct wmOperatorType *ot); @@ -292,12 +290,13 @@ void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot); void NODE_OT_switch_view_update(struct wmOperatorType *ot); -/* Note: clipboard_cut is a simple macro of copy + delete */ +/* NOTE: clipboard_cut is a simple macro of copy + delete. */ void NODE_OT_clipboard_copy(struct wmOperatorType *ot); void NODE_OT_clipboard_paste(struct wmOperatorType *ot); void NODE_OT_tree_socket_add(struct wmOperatorType *ot); void NODE_OT_tree_socket_remove(struct wmOperatorType *ot); +void NODE_OT_tree_socket_change_type(struct wmOperatorType *ot); void NODE_OT_tree_socket_move(struct wmOperatorType *ot); void NODE_OT_shader_script_update(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index e35b444aa11..610c2889e7a 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -119,6 +119,7 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_tree_socket_add); WM_operatortype_append(NODE_OT_tree_socket_remove); + WM_operatortype_append(NODE_OT_tree_socket_change_type); WM_operatortype_append(NODE_OT_tree_socket_move); WM_operatortype_append(NODE_OT_cryptomatte_layer_add); @@ -157,7 +158,7 @@ void ED_operatormacros_node(void) WM_operatortype_macro_define(ot, "NODE_OT_attach"); WM_operatortype_macro_define(ot, "NODE_OT_insert_offset"); - /* Note: Currently not in a default keymap or menu due to messy keymaps + /* NOTE: Currently not in a default keymap or menu due to messy keymaps * and tricky invoke functionality. * Kept around in case users want to make own shortcuts. */ diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 5c251b47746..4e6e8937bb4 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -36,15 +36,19 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_screen.h" #include "ED_node.h" /* own include */ #include "ED_render.h" #include "ED_screen.h" +#include "ED_spreadsheet.h" #include "ED_util.h" #include "RNA_access.h" #include "RNA_define.h" +#include "DEG_depsgraph.h" + #include "WM_api.h" #include "WM_types.h" @@ -160,6 +164,11 @@ bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node) return true; } } + if (current_node->type == GEO_NODE_VIEWER) { + if (ntree_check_nodes_connected(ntree, node, current_node)) { + return true; + } + } } return false; } @@ -610,14 +619,14 @@ static int node_link_viewer(const bContext *C, bNode *tonode) if (tonode == nullptr || BLI_listbase_is_empty(&tonode->outputs)) { return OPERATOR_CANCELLED; } - if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { return OPERATOR_CANCELLED; } /* get viewer */ bNode *viewer_node = nullptr; LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { - if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { if (node->flag & NODE_DO_OUTPUT) { viewer_node = node; break; @@ -627,7 +636,7 @@ static int node_link_viewer(const bContext *C, bNode *tonode) /* no viewer, we make one active */ if (viewer_node == nullptr) { LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { - if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { node->flag |= NODE_DO_OUTPUT; viewer_node = node; break; @@ -686,7 +695,8 @@ static int node_link_viewer(const bContext *C, bNode *tonode) /* add a new viewer if none exists yet */ if (!viewer_node) { /* XXX location is a quick hack, just place it next to the linked socket */ - viewer_node = node_add_node(C, nullptr, CMP_NODE_VIEWER, sock->locx + 100, sock->locy); + const int viewer_type = ED_node_is_compositor(snode) ? CMP_NODE_VIEWER : GEO_NODE_VIEWER; + viewer_node = node_add_node(C, nullptr, viewer_type, sock->locx + 100, sock->locy); if (!viewer_node) { return OPERATOR_CANCELLED; } @@ -712,8 +722,13 @@ static int node_link_viewer(const bContext *C, bNode *tonode) /* make sure the dependency sorting is updated */ snode->edittree->update |= NTREE_UPDATE_LINKS; } + if (ED_node_is_geometry(snode)) { + ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_node); + } + ntreeUpdateTree(CTX_data_main(C), snode->edittree); snode_update(snode, viewer_node); + DEG_id_tag_update(&snode->edittree->id, 0); } return OPERATOR_FINISHED; @@ -739,6 +754,15 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } +static bool node_active_link_viewer_poll(bContext *C) +{ + if (!ED_operator_node_editable(C)) { + return false; + } + SpaceNode *snode = CTX_wm_space_node(C); + return ED_node_is_compositor(snode) || ED_node_is_geometry(snode); +} + void NODE_OT_link_viewer(wmOperatorType *ot) { /* identifiers */ @@ -748,7 +772,7 @@ void NODE_OT_link_viewer(wmOperatorType *ot) /* api callbacks */ ot->exec = node_active_link_viewer_exec; - ot->poll = composite_node_editable; + ot->poll = node_active_link_viewer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1309,7 +1333,7 @@ static int cut_links_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(CTX_wm_manager(C), bmain); LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) { - if (nodeLinkIsHidden(link)) { + if (node_link_is_hidden_or_dimmed(®ion->v2d, link)) { continue; } @@ -1406,7 +1430,7 @@ static int mute_links_exec(bContext *C, wmOperator *op) /* Count intersected links and clear test flag. */ int tot = 0; LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { - if (nodeLinkIsHidden(link)) { + if (node_link_is_hidden_or_dimmed(®ion->v2d, link)) { continue; } link->flag &= ~NODE_LINK_TEST; @@ -1420,7 +1444,7 @@ static int mute_links_exec(bContext *C, wmOperator *op) /* Mute links. */ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { - if (nodeLinkIsHidden(link) || (link->flag & NODE_LINK_TEST)) { + if (node_link_is_hidden_or_dimmed(®ion->v2d, link) || (link->flag & NODE_LINK_TEST)) { continue; } @@ -1435,7 +1459,7 @@ static int mute_links_exec(bContext *C, wmOperator *op) /* Clear remaining test flags. */ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { - if (nodeLinkIsHidden(link)) { + if (node_link_is_hidden_or_dimmed(®ion->v2d, link)) { continue; } link->flag &= ~NODE_LINK_TEST; @@ -1871,9 +1895,11 @@ static bool ed_node_link_conditions(ScrArea *area, return false; } + ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); + /* test node for links */ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { - if (nodeLinkIsHidden(link)) { + if (node_link_is_hidden_or_dimmed(®ion->v2d, link)) { continue; } @@ -1904,13 +1930,15 @@ void ED_node_link_intersect_test(ScrArea *area, int test) return; } + ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); + /* find link to select/highlight */ bNodeLink *selink = nullptr; float dist_best = FLT_MAX; LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { float coord_array[NODE_LINK_RESOL + 1][2]; - if (nodeLinkIsHidden(link)) { + if (node_link_is_hidden_or_dimmed(®ion->v2d, link)) { continue; } diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 41820cd813c..a081cc83481 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -44,6 +44,7 @@ #include "ED_node.h" /* own include */ #include "ED_screen.h" #include "ED_select_utils.h" +#include "ED_spreadsheet.h" #include "ED_view3d.h" #include "RNA_access.h" @@ -330,7 +331,7 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo pref_len_act = BLI_str_partition_ex_utf8( node_act->name, nullptr, delims, &sep, &suf_act, from_right); - /* Note: in case we are searching for suffix, and found none, use whole name as suffix. */ + /* NOTE: in case we are searching for suffix, and found none, use whole name as suffix. */ if (from_right && !(sep && suf_act)) { pref_len_act = 0; suf_act = node_act->name; @@ -469,7 +470,7 @@ void node_select_single(bContext *C, bNode *node) } nodeSetSelected(node, true); - ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed); + ED_node_set_active(bmain, snode, snode->edittree, node, &active_texture_changed); ED_node_set_active_viewer_key(snode); ED_node_sort(snode->edittree); @@ -606,12 +607,18 @@ static int node_mouse_select(bContext *C, /* update node order */ if (ret_value != OPERATOR_CANCELLED) { bool active_texture_changed = false; + bool viewer_node_changed = false; if (node != nullptr && ret_value != OPERATOR_RUNNING_MODAL) { - ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed); + viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER; + ED_node_set_active(bmain, snode, snode->edittree, node, &active_texture_changed); + } + else if (node != nullptr && node->type == GEO_NODE_VIEWER) { + ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, node); } ED_node_set_active_viewer_key(snode); ED_node_sort(snode->edittree); - if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) { + if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) || + viewer_node_changed) { DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE); } diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index 93599bc3c2a..10ad83e4fe9 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -364,7 +364,7 @@ static void ui_node_link_items(NodeLinkArg *arg, NodeLinkItem *item = &items[i]; item->socket_index = index; - /* note: int stemp->type is not fully reliable, not used for node group + /* NOTE: int stemp->type is not fully reliable, not used for node group * interface sockets. use the typeinfo->type instead. */ item->socket_type = stemp->typeinfo->type; diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index f20a9409d90..ff848a7bb95 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -345,7 +345,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) ScrArea *area = params->area; wmNotifier *wmn = params->notifier; - /* note, ED_area_tag_refresh will re-execute compositor */ + /* NOTE: #ED_area_tag_refresh will re-execute compositor. */ SpaceNode *snode = area->spacedata.first; /* shaderfrom is only used for new shading nodes, otherwise all shaders are from objects */ short shader_type = snode->shaderfrom; @@ -563,7 +563,7 @@ static SpaceLink *node_duplicate(SpaceLink *sl) BLI_listbase_clear(&snoden->runtime->linkdrag); } - /* Note: no need to set node tree user counts, + /* NOTE: no need to set node tree user counts, * the editor only keeps at least 1 (id_us_ensure_real), * which is already done by the original SpaceNode. */ @@ -651,6 +651,10 @@ static void node_main_region_init(wmWindowManager *wm, ARegion *region) lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW); WM_event_add_dropbox_handler(®ion->handlers, lb); + + /* The backdrop image gizmo needs to change together with the view. So always refresh gizmos on + * region size changes. */ + WM_gizmomap_tag_refresh(region->gizmo_map); } static void node_main_region_draw(const bContext *C, ARegion *region) @@ -1094,8 +1098,6 @@ void ED_spacetype_node(void) art->draw = node_buttons_region_draw; BLI_addhead(&st->regiontypes, art); - node_buttons_register(art); - /* regions: toolbar */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); art->regionid = RGN_TYPE_TOOLS; |