Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_node/node_draw.cc
| Show First 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
| #include "NOD_geometry_nodes_eval_log.hh" | #include "NOD_geometry_nodes_eval_log.hh" | ||||
| #include "NOD_node_declaration.hh" | #include "NOD_node_declaration.hh" | ||||
| #include "FN_field_cpp_type.hh" | #include "FN_field_cpp_type.hh" | ||||
| #include "node_intern.hh" /* own include */ | #include "node_intern.hh" /* own include */ | ||||
| #include <iomanip> | |||||
| #ifdef WITH_COMPOSITOR | #ifdef WITH_COMPOSITOR | ||||
| # include "COM_compositor.h" | # include "COM_compositor.h" | ||||
| #endif | #endif | ||||
| using blender::Map; | using blender::Map; | ||||
| using blender::Set; | using blender::Set; | ||||
| using blender::Span; | using blender::Span; | ||||
| using blender::Vector; | using blender::Vector; | ||||
| ▲ Show 20 Lines • Show All 740 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| struct SocketTooltipData { | struct SocketTooltipData { | ||||
| bNodeTree *ntree; | bNodeTree *ntree; | ||||
| bNode *node; | bNode *node; | ||||
| bNodeSocket *socket; | bNodeSocket *socket; | ||||
| }; | }; | ||||
| static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log, | static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss) | ||||
| std::stringstream &ss) | |||||
| { | { | ||||
| auto id_to_inspection_string = [&](ID *id, short idcode) { | auto id_to_inspection_string = [&](ID *id, short idcode) { | ||||
| ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(idcode) << ")"; | ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(idcode) << ")"; | ||||
| }; | }; | ||||
| const GPointer value = value_log.value(); | |||||
| const CPPType &type = *value.type(); | const CPPType &type = *value.type(); | ||||
| const void *buffer = value.get(); | |||||
| if (type.is<Object *>()) { | if (type.is<Object *>()) { | ||||
| id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB); | id_to_inspection_string((ID *)buffer, ID_OB); | ||||
| } | } | ||||
| else if (type.is<Material *>()) { | else if (type.is<Material *>()) { | ||||
| id_to_inspection_string((ID *)*value.get<Material *>(), ID_MA); | id_to_inspection_string((ID *)buffer, ID_MA); | ||||
| } | } | ||||
| else if (type.is<Tex *>()) { | else if (type.is<Tex *>()) { | ||||
| id_to_inspection_string((ID *)*value.get<Tex *>(), ID_TE); | id_to_inspection_string((ID *)buffer, ID_TE); | ||||
| } | } | ||||
| else if (type.is<Image *>()) { | else if (type.is<Image *>()) { | ||||
| id_to_inspection_string((ID *)*value.get<Image *>(), ID_IM); | id_to_inspection_string((ID *)buffer, ID_IM); | ||||
| } | } | ||||
| else if (type.is<Collection *>()) { | else if (type.is<Collection *>()) { | ||||
| id_to_inspection_string((ID *)*value.get<Collection *>(), ID_GR); | id_to_inspection_string((ID *)buffer, ID_GR); | ||||
| } | |||||
| } | } | ||||
| else if (type.is<int>()) { | |||||
| static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &value_log, | |||||
| std::stringstream &ss) | |||||
| { | |||||
| const CPPType &type = value_log.type(); | |||||
| const GField &field = value_log.field(); | |||||
| const Span<std::string> input_tooltips = value_log.input_tooltips(); | |||||
| if (input_tooltips.is_empty()) { | |||||
| if (field) { | |||||
| BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); | |||||
| blender::fn::evaluate_constant_field(field, buffer); | |||||
| if (type.is<int>()) { | |||||
| ss << *(int *)buffer << TIP_(" (Integer)"); | ss << *(int *)buffer << TIP_(" (Integer)"); | ||||
| } | } | ||||
| else if (type.is<float>()) { | else if (type.is<float>()) { | ||||
| ss << *(float *)buffer << TIP_(" (Float)"); | ss << *(float *)buffer << TIP_(" (Float)"); | ||||
| } | } | ||||
| else if (type.is<blender::float3>()) { | else if (type.is<blender::float3>()) { | ||||
| ss << *(blender::float3 *)buffer << TIP_(" (Vector)"); | ss << *(blender::float3 *)buffer << TIP_(" (Vector)"); | ||||
| } | } | ||||
| else if (type.is<bool>()) { | else if (type.is<bool>()) { | ||||
| ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)"); | ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)"); | ||||
| } | } | ||||
| else if (type.is<std::string>()) { | else if (type.is<std::string>()) { | ||||
| ss << *(std::string *)buffer << TIP_(" (String)"); | ss << *(std::string *)buffer << TIP_(" (String)"); | ||||
| } | } | ||||
| } | |||||
| static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &value_log, | |||||
| std::stringstream &ss) | |||||
| { | |||||
| const CPPType &type = value_log.type(); | |||||
| const GField &field = value_log.field(); | |||||
| const Span<std::string> input_tooltips = value_log.input_tooltips(); | |||||
| if (input_tooltips.is_empty()) { | |||||
| if (field) { | |||||
| BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); | |||||
| blender::fn::evaluate_constant_field(field, buffer); | |||||
| create_inspection_string_for_generic_value({type, buffer}, ss); | |||||
| type.destruct(buffer); | type.destruct(buffer); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Constant values should always be logged. */ | /* Constant values should always be logged. */ | ||||
| BLI_assert_unreachable(); | BLI_assert_unreachable(); | ||||
| ss << "Value has not been logged"; | ss << "Value has not been logged"; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | static std::optional<std::string> create_socket_inspection_string(bContext *C, | ||||
| const geo_log::ValueLog *value_log = socket_log->value(); | const geo_log::ValueLog *value_log = socket_log->value(); | ||||
| if (value_log == nullptr) { | if (value_log == nullptr) { | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| std::stringstream ss; | std::stringstream ss; | ||||
| if (const geo_log::GenericValueLog *generic_value_log = | if (const geo_log::GenericValueLog *generic_value_log = | ||||
| dynamic_cast<const geo_log::GenericValueLog *>(value_log)) { | dynamic_cast<const geo_log::GenericValueLog *>(value_log)) { | ||||
| create_inspection_string_for_generic_value(*generic_value_log, ss); | create_inspection_string_for_generic_value(generic_value_log->value(), ss); | ||||
| } | } | ||||
| if (const geo_log::GFieldValueLog *gfield_value_log = | if (const geo_log::GFieldValueLog *gfield_value_log = | ||||
| dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) { | dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) { | ||||
| create_inspection_string_for_gfield(*gfield_value_log, ss); | create_inspection_string_for_gfield(*gfield_value_log, ss); | ||||
| } | } | ||||
| else if (const geo_log::GeometryValueLog *geo_value_log = | else if (const geo_log::GeometryValueLog *geo_value_log = | ||||
| dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) { | dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) { | ||||
| create_inspection_string_for_geometry(*geo_value_log, ss); | create_inspection_string_for_geometry(*geo_value_log, ss); | ||||
| ▲ Show 20 Lines • Show All 537 Lines • ▼ Show 20 Lines | uiBut *but = uiDefIconBut(node.block, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| nullptr); | nullptr); | ||||
| UI_but_func_tooltip_set(but, node_errors_tooltip_fn, tooltip_data, MEM_freeN); | UI_but_func_tooltip_set(but, node_errors_tooltip_fn, tooltip_data, MEM_freeN); | ||||
| UI_block_emboss_set(node.block, UI_EMBOSS); | UI_block_emboss_set(node.block, UI_EMBOSS); | ||||
| } | } | ||||
| static void get_exec_time_other_nodes(const bNode *node, | |||||
| const SpaceNode *snode, | |||||
| std::chrono::microseconds &exec_time, | |||||
| int &node_count) | |||||
| { | |||||
| if (node->type == NODE_GROUP) { | |||||
| const geo_log::TreeLog *root_tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context( | |||||
| *snode); | |||||
| if (root_tree_log == nullptr) { | |||||
| return; | |||||
| } | |||||
| const geo_log::TreeLog *tree_log = root_tree_log->lookup_child_log(node->name); | |||||
| if (tree_log == nullptr) { | |||||
| return; | |||||
| } | |||||
| tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) { | |||||
| exec_time += node_log.execution_time(); | |||||
| node_count++; | |||||
| }); | |||||
| } | |||||
| else { | |||||
| const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context( | |||||
| *snode, *node); | |||||
| if (node_log) { | |||||
| exec_time += node_log->execution_time(); | |||||
| node_count++; | |||||
| } | |||||
| } | |||||
| } | |||||
| static std::chrono::microseconds node_get_execution_time(const bNodeTree *ntree, | |||||
| const bNode *node, | |||||
| const SpaceNode *snode, | |||||
| int &node_count) | |||||
| { | |||||
| std::chrono::microseconds exec_time = std::chrono::microseconds::zero(); | |||||
| if (node->type == NODE_GROUP_OUTPUT) { | |||||
| const geo_log::TreeLog *tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context( | |||||
| *snode); | |||||
| if (tree_log == nullptr) { | |||||
| return exec_time; | |||||
| } | |||||
| tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) { | |||||
| exec_time += node_log.execution_time(); | |||||
| node_count++; | |||||
| }); | |||||
| } | |||||
| else if (node->type == NODE_FRAME) { | |||||
| /* Could be cached in the future if this recursive code turns out to be slow. */ | |||||
| LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) { | |||||
| if (tnode->parent != node) { | |||||
| continue; | |||||
| } | |||||
| if (tnode->type == NODE_FRAME) { | |||||
| exec_time += node_get_execution_time(ntree, tnode, snode, node_count); | |||||
| } | |||||
| else { | |||||
| get_exec_time_other_nodes(tnode, snode, exec_time, node_count); | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| get_exec_time_other_nodes(node, snode, exec_time, node_count); | |||||
| } | |||||
| return exec_time; | |||||
| } | |||||
| static std::string node_get_execution_time_label(const SpaceNode *snode, const bNode *node) | |||||
| { | |||||
| int node_count = 0; | |||||
| std::chrono::microseconds exec_time = node_get_execution_time( | |||||
| snode->nodetree, node, snode, node_count); | |||||
| if (node_count == 0) { | |||||
| return std::string(""); | |||||
| } | |||||
| uint64_t exec_time_us = exec_time.count(); | |||||
| /* Don't show time if execution time is 0 microseconds. */ | |||||
| if (exec_time_us == 0) { | |||||
| return std::string("-"); | |||||
| } | |||||
| if (exec_time_us < 100) { | |||||
| return std::string("< 0.1 ms"); | |||||
| } | |||||
| int precision = 0; | |||||
| /* Show decimal if value is below 1ms */ | |||||
| if (exec_time_us < 1000) { | |||||
| precision = 2; | |||||
| } | |||||
| else if (exec_time_us < 10000) { | |||||
| precision = 1; | |||||
| } | |||||
| std::stringstream stream; | |||||
| stream << std::fixed << std::setprecision(precision) << (exec_time_us / 1000.0f); | |||||
| return stream.str() + " ms"; | |||||
| } | |||||
| struct NodeExtraInfoRow { | |||||
| std::string text; | |||||
| const char *tooltip; | |||||
| int icon; | |||||
| }; | |||||
| static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode *snode, const bNode *node) | |||||
| { | |||||
| Vector<NodeExtraInfoRow> rows; | |||||
| if (!(snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS)) { | |||||
| return rows; | |||||
| } | |||||
| if (snode->overlay.flag & SN_OVERLAY_SHOW_TIMINGS && snode->edittree->type == NTREE_GEOMETRY && | |||||
| (ELEM(node->typeinfo->nclass, NODE_CLASS_GEOMETRY, NODE_CLASS_GROUP, NODE_CLASS_ATTRIBUTE) || | |||||
| ELEM(node->type, NODE_FRAME, NODE_GROUP_OUTPUT))) { | |||||
| NodeExtraInfoRow row; | |||||
| row.text = node_get_execution_time_label(snode, node); | |||||
| if (!row.text.empty()) { | |||||
| row.tooltip = TIP_( | |||||
| "The execution time from the node tree's latest evaluation. For frame and group nodes, " | |||||
| "the time for all sub-nodes"); | |||||
| row.icon = ICON_PREVIEW_RANGE; | |||||
| rows.append(std::move(row)); | |||||
| } | |||||
| } | |||||
| const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(*snode, | |||||
| *node); | |||||
| if (node_log != nullptr) { | |||||
| for (const std::string &message : node_log->debug_messages()) { | |||||
| NodeExtraInfoRow row; | |||||
| row.text = message; | |||||
| row.icon = ICON_INFO; | |||||
| rows.append(std::move(row)); | |||||
| } | |||||
| } | |||||
| return rows; | |||||
| } | |||||
| static void node_draw_extra_info_row(const bNode *node, | |||||
| const rctf *rect, | |||||
| const int row, | |||||
| const NodeExtraInfoRow &extra_info_row) | |||||
| { | |||||
| uiBut *but_timing = uiDefBut(node->block, | |||||
| UI_BTYPE_LABEL, | |||||
| 0, | |||||
| extra_info_row.text.c_str(), | |||||
| (int)(rect->xmin + 4.0f * U.dpi_fac + NODE_MARGIN_X + 0.4f), | |||||
| (int)(rect->ymin + row * (20.0f * U.dpi_fac)), | |||||
| (short)(rect->xmax - rect->xmin), | |||||
| (short)NODE_DY, | |||||
| nullptr, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| ""); | |||||
| UI_block_emboss_set(node->block, UI_EMBOSS_NONE); | |||||
| uiBut *but_icon = uiDefIconBut(node->block, | |||||
| UI_BTYPE_BUT, | |||||
| 0, | |||||
| extra_info_row.icon, | |||||
| (int)(rect->xmin + 6.0f * U.dpi_fac), | |||||
| (int)(rect->ymin + row * (20.0f * U.dpi_fac)), | |||||
| NODE_HEADER_ICON_SIZE * 0.8f, | |||||
| UI_UNIT_Y, | |||||
| nullptr, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| extra_info_row.tooltip); | |||||
| UI_block_emboss_set(node->block, UI_EMBOSS); | |||||
| if (node->flag & NODE_MUTED) { | |||||
| UI_but_flag_enable(but_timing, UI_BUT_INACTIVE); | |||||
| UI_but_flag_enable(but_icon, UI_BUT_INACTIVE); | |||||
| } | |||||
| } | |||||
| void node_draw_extra_info_panel(const SpaceNode *snode, const bNode *node) | |||||
| { | |||||
| Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(snode, node); | |||||
| if (extra_info_rows.size() == 0) { | |||||
| return; | |||||
| } | |||||
| const rctf *rct = &node->totr; | |||||
| float color[4]; | |||||
| rctf extra_info_rect; | |||||
| if (node->type == NODE_FRAME) { | |||||
| extra_info_rect.xmin = rct->xmin; | |||||
| extra_info_rect.xmax = rct->xmin + 95.0f * U.dpi_fac; | |||||
| extra_info_rect.ymin = rct->ymin + 2.0f * U.dpi_fac; | |||||
| extra_info_rect.ymax = rct->ymin + 2.0f * U.dpi_fac; | |||||
| } | |||||
| else { | |||||
| extra_info_rect.xmin = rct->xmin + 3.0f * U.dpi_fac; | |||||
| extra_info_rect.xmax = rct->xmin + 95.0f * U.dpi_fac; | |||||
| extra_info_rect.ymin = rct->ymax; | |||||
| extra_info_rect.ymax = rct->ymax + extra_info_rows.size() * (20.0f * U.dpi_fac); | |||||
| if (node->flag & NODE_MUTED) { | |||||
| UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color); | |||||
| } | |||||
| else { | |||||
| UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.75f, color); | |||||
| } | |||||
| color[3] -= 0.35f; | |||||
| UI_draw_roundbox_corner_set( | |||||
| UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT & | |||||
| ((rct->xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL)); | |||||
| UI_draw_roundbox_4fv(&extra_info_rect, true, BASIS_RAD, color); | |||||
| /* Draw outline. */ | |||||
| const float outline_width = 1.0f; | |||||
| extra_info_rect.xmin = rct->xmin + 3.0f * U.dpi_fac - outline_width; | |||||
| extra_info_rect.xmax = rct->xmin + 95.0f * U.dpi_fac + outline_width; | |||||
| extra_info_rect.ymin = rct->ymax - outline_width; | |||||
| extra_info_rect.ymax = rct->ymax + outline_width + | |||||
| extra_info_rows.size() * (20.0f * U.dpi_fac); | |||||
| UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color); | |||||
| UI_draw_roundbox_corner_set( | |||||
| UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT & | |||||
| ((rct->xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL)); | |||||
| UI_draw_roundbox_4fv(&extra_info_rect, false, BASIS_RAD, color); | |||||
| } | |||||
| for (int row : extra_info_rows.index_range()) { | |||||
| node_draw_extra_info_row(node, &extra_info_rect, row, extra_info_rows[row]); | |||||
| } | |||||
| } | |||||
| static void node_draw_basis(const bContext *C, | static void node_draw_basis(const bContext *C, | ||||
| const View2D *v2d, | const View2D *v2d, | ||||
| const SpaceNode *snode, | const SpaceNode *snode, | ||||
| bNodeTree *ntree, | bNodeTree *ntree, | ||||
| bNode *node, | bNode *node, | ||||
| bNodeInstanceKey key) | bNodeInstanceKey key) | ||||
| { | { | ||||
| const float iconbutw = NODE_HEADER_ICON_SIZE; | const float iconbutw = NODE_HEADER_ICON_SIZE; | ||||
| Show All 9 Lines | static void node_draw_basis(const bContext *C, | ||||
| node_draw_shadow(snode, node, BASIS_RAD, 1.0f); | node_draw_shadow(snode, node, BASIS_RAD, 1.0f); | ||||
| rctf *rct = &node->totr; | rctf *rct = &node->totr; | ||||
| float color[4]; | float color[4]; | ||||
| int color_id = node_get_colorid(node); | int color_id = node_get_colorid(node); | ||||
| GPU_line_width(1.0f); | GPU_line_width(1.0f); | ||||
| node_draw_extra_info_panel(snode, node); | |||||
| /* Header. */ | /* Header. */ | ||||
| { | { | ||||
| const rctf rect = { | const rctf rect = { | ||||
| rct->xmin, | rct->xmin, | ||||
| rct->xmax, | rct->xmax, | ||||
| rct->ymax - NODE_DY, | rct->ymax - NODE_DY, | ||||
| rct->ymax, | rct->ymax, | ||||
| }; | }; | ||||
| ▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | /* Outline. */ | ||||
| else { | else { | ||||
| UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color_outline); | UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color_outline); | ||||
| } | } | ||||
| UI_draw_roundbox_corner_set(UI_CNR_ALL); | UI_draw_roundbox_corner_set(UI_CNR_ALL); | ||||
| UI_draw_roundbox_4fv(&rect, false, BASIS_RAD, color_outline); | UI_draw_roundbox_4fv(&rect, false, BASIS_RAD, color_outline); | ||||
| } | } | ||||
| float scale; | |||||
| UI_view2d_scale_get(v2d, &scale, nullptr); | |||||
| /* Skip slow socket drawing if zoom is small. */ | |||||
| if (scale > 0.2f) { | |||||
| node_draw_sockets(v2d, C, ntree, node, true, false); | node_draw_sockets(v2d, C, ntree, node, true, false); | ||||
| } | |||||
| /* Preview. */ | /* Preview. */ | ||||
| bNodeInstanceHash *previews = (bNodeInstanceHash *)CTX_data_pointer_get(C, "node_previews").data; | bNodeInstanceHash *previews = (bNodeInstanceHash *)CTX_data_pointer_get(C, "node_previews").data; | ||||
| if (node->flag & NODE_PREVIEW && previews) { | if (node->flag & NODE_PREVIEW && previews) { | ||||
| bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key); | bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key); | ||||
| if (preview && (preview->xsize && preview->ysize)) { | if (preview && (preview->xsize && preview->ysize)) { | ||||
| if (preview->rect && !BLI_rctf_is_empty(&node->prvr)) { | if (preview->rect && !BLI_rctf_is_empty(&node->prvr)) { | ||||
| node_draw_preview(preview, &node->prvr); | node_draw_preview(preview, &node->prvr); | ||||
| ▲ Show 20 Lines • Show All 251 Lines • ▼ Show 20 Lines | static void count_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode) | ||||
| Map<bNodeSocket *, int> counts; | Map<bNodeSocket *, int> counts; | ||||
| LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { | LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { | ||||
| if (link->tosock->flag & SOCK_MULTI_INPUT) { | if (link->tosock->flag & SOCK_MULTI_INPUT) { | ||||
| int &count = counts.lookup_or_add(link->tosock, 0); | int &count = counts.lookup_or_add(link->tosock, 0); | ||||
| count++; | count++; | ||||
| } | } | ||||
| } | } | ||||
| /* Count temporary links going into this socket. */ | /* Count temporary links going into this socket. */ | ||||
| LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { | if (snode->runtime->linkdrag) { | ||||
| LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { | for (const bNodeLink *link : snode->runtime->linkdrag->links) { | ||||
| bNodeLink *link = (bNodeLink *)linkdata->data; | |||||
| if (link->tosock && (link->tosock->flag & SOCK_MULTI_INPUT)) { | if (link->tosock && (link->tosock->flag & SOCK_MULTI_INPUT)) { | ||||
| int &count = counts.lookup_or_add(link->tosock, 0); | int &count = counts.lookup_or_add(link->tosock, 0); | ||||
| count++; | count++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { | LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { | ||||
| if (socket->flag & SOCK_MULTI_INPUT) { | if (socket->flag & SOCK_MULTI_INPUT) { | ||||
| socket->total_inputs = counts.lookup_default(socket, 0); | socket->total_inputs = counts.lookup_default(socket, 0); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 242 Lines • ▼ Show 20 Lines | if (ntree) { | ||||
| } | } | ||||
| draw_nodetree(C, region, ntree, path->parent_key); | draw_nodetree(C, region, ntree, path->parent_key); | ||||
| } | } | ||||
| /* Temporary links. */ | /* Temporary links. */ | ||||
| GPU_blend(GPU_BLEND_ALPHA); | GPU_blend(GPU_BLEND_ALPHA); | ||||
| GPU_line_smooth(true); | GPU_line_smooth(true); | ||||
| LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { | if (snode->runtime->linkdrag) { | ||||
| LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { | for (const bNodeLink *link : snode->runtime->linkdrag->links) { | ||||
| node_draw_link(C, v2d, snode, (bNodeLink *)linkdata->data); | node_draw_link(C, v2d, snode, link); | ||||
| } | } | ||||
| } | } | ||||
| GPU_line_smooth(false); | GPU_line_smooth(false); | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| if (snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && snode->flag & SNODE_SHOW_GPENCIL) { | if (snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && snode->flag & SNODE_SHOW_GPENCIL) { | ||||
| /* Draw grease-pencil annotations. */ | /* Draw grease-pencil annotations. */ | ||||
| ED_annotation_draw_view2d(C, true); | ED_annotation_draw_view2d(C, true); | ||||
| Show All 28 Lines | |||||