diff options
author | Hans Goudey <h.goudey@me.com> | 2021-02-16 19:55:10 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2021-02-16 19:55:10 +0300 |
commit | 520d965c77f9109492013d33cff659cd6055ff11 (patch) | |
tree | 5fbf5e6e8ffc917d158f6a46634209442efc3182 /source/blender/editors/space_node/node_draw.c | |
parent | 8971018eb64a68119687c74db875fd45f89cbdf8 (diff) |
Cleanup: Compile node_draw.c with C++
This will allow using C++ data structures to draw node error messages.
This required removing a forward declared enum for grease pencil undo.
Compiles with clang tidy.
Diffstat (limited to 'source/blender/editors/space_node/node_draw.c')
-rw-r--r-- | source/blender/editors/space_node/node_draw.c | 2036 |
1 files changed, 0 insertions, 2036 deletions
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c deleted file mode 100644 index c7be5f848f7..00000000000 --- a/source/blender/editors/space_node/node_draw.c +++ /dev/null @@ -1,2036 +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) 2008 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup spnode - * \brief higher level node drawing for the node editor. - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_light_types.h" -#include "DNA_linestyle_types.h" -#include "DNA_material_types.h" -#include "DNA_node_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_texture_types.h" -#include "DNA_world_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" - -#include "BLT_translation.h" - -#include "BKE_context.h" -#include "BKE_lib_id.h" -#include "BKE_main.h" -#include "BKE_node.h" - -#include "DEG_depsgraph.h" - -#include "BLF_api.h" - -#include "BIF_glutil.h" - -#include "GPU_framebuffer.h" -#include "GPU_immediate.h" -#include "GPU_immediate_util.h" -#include "GPU_matrix.h" -#include "GPU_state.h" -#include "GPU_viewport.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_gpencil.h" -#include "ED_node.h" -#include "ED_space_api.h" - -#include "UI_resources.h" -#include "UI_view2d.h" - -#include "RNA_access.h" - -#include "node_intern.h" /* own include */ - -#ifdef WITH_COMPOSITOR -# include "COM_compositor.h" -#endif - -/* XXX interface.h */ -extern void ui_draw_dropshadow( - const rctf *rct, float radius, float aspect, float alpha, int select); - -float ED_node_grid_size(void) -{ - return U.widget_unit; -} - -void ED_node_tree_update(const bContext *C) -{ - SpaceNode *snode = CTX_wm_space_node(C); - if (snode) { - snode_set_context(C); - - id_us_ensure_real(&snode->nodetree->id); - } -} - -/* id is supposed to contain a node tree */ -static bNodeTree *node_tree_from_ID(ID *id) -{ - if (id) { - if (GS(id->name) == ID_NT) { - return (bNodeTree *)id; - } - return ntreeFromID(id); - } - - return NULL; -} - -void ED_node_tag_update_id(ID *id) -{ - bNodeTree *ntree = node_tree_from_ID(id); - if (id == NULL || ntree == NULL) { - return; - } - - /* TODO(sergey): With the new dependency graph it - * should be just enough to only tag ntree itself, - * all the users of this tree will have update - * flushed from the tree, - */ - DEG_id_tag_update(&ntree->id, 0); - - if (ntree->type == NTREE_SHADER) { - DEG_id_tag_update(id, 0); - - if (GS(id->name) == ID_MA) { - WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id); - } - else if (GS(id->name) == ID_LA) { - WM_main_add_notifier(NC_LAMP | ND_LIGHTING, id); - } - else if (GS(id->name) == ID_WO) { - WM_main_add_notifier(NC_WORLD | ND_WORLD, id); - } - } - else if (ntree->type == NTREE_COMPOSIT) { - WM_main_add_notifier(NC_SCENE | ND_NODES, id); - } - else if (ntree->type == NTREE_TEXTURE) { - DEG_id_tag_update(id, 0); - WM_main_add_notifier(NC_TEXTURE | ND_NODES, id); - } - else if (ntree->type == NTREE_GEOMETRY) { - WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id); - } - else if (id == &ntree->id) { - /* node groups */ - DEG_id_tag_update(id, 0); - } -} - -void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node) -{ - if (!ntree) { - return; - } - - bool do_tag_update = true; - if (node != NULL) { - if (!node_connected_to_output(bmain, ntree, node)) { - do_tag_update = false; - } - } - - /* look through all datablocks, to support groups */ - if (do_tag_update) { - FOREACH_NODETREE_BEGIN (bmain, tntree, id) { - /* check if nodetree uses the group */ - if (ntreeHasTree(tntree, ntree)) { - ED_node_tag_update_id(id); - } - } - FOREACH_NODETREE_END; - } - - if (ntree->type == NTREE_TEXTURE) { - ntreeTexCheckCyclics(ntree); - } -} - -static bool compare_nodes(const bNode *a, const bNode *b) -{ - /* These tell if either the node or any of the parent nodes is selected. - * A selected parent means an unselected node is also in foreground! - */ - bool a_select = (a->flag & NODE_SELECT) != 0, b_select = (b->flag & NODE_SELECT) != 0; - bool a_active = (a->flag & NODE_ACTIVE) != 0, b_active = (b->flag & NODE_ACTIVE) != 0; - - /* if one is an ancestor of the other */ - /* XXX there might be a better sorting algorithm for stable topological sort, - * this is O(n^2) worst case */ - for (bNode *parent = a->parent; parent; parent = parent->parent) { - /* if b is an ancestor, it is always behind a */ - if (parent == b) { - return true; - } - /* any selected ancestor moves the node forward */ - if (parent->flag & NODE_ACTIVE) { - a_active = 1; - } - if (parent->flag & NODE_SELECT) { - a_select = 1; - } - } - for (bNode *parent = b->parent; parent; parent = parent->parent) { - /* if a is an ancestor, it is always behind b */ - if (parent == a) { - return false; - } - /* any selected ancestor moves the node forward */ - if (parent->flag & NODE_ACTIVE) { - b_active = 1; - } - if (parent->flag & NODE_SELECT) { - b_select = 1; - } - } - - /* if one of the nodes is in the background and the other not */ - if ((a->flag & NODE_BACKGROUND) && !(b->flag & NODE_BACKGROUND)) { - return false; - } - if (!(a->flag & NODE_BACKGROUND) && (b->flag & NODE_BACKGROUND)) { - return true; - } - - /* if one has a higher selection state (active > selected > nothing) */ - if (!b_active && a_active) { - return true; - } - if (!b_select && (a_active || a_select)) { - return true; - } - - return false; -} - -/* Sorts nodes by selection: unselected nodes first, then selected, - * then the active node at the very end. Relative order is kept intact! - */ -void ED_node_sort(bNodeTree *ntree) -{ - /* merge sort is the algorithm of choice here */ - int totnodes = BLI_listbase_count(&ntree->nodes); - - int k = 1; - while (k < totnodes) { - bNode *first_a = ntree->nodes.first; - bNode *first_b = first_a; - - do { - /* setup first_b pointer */ - for (int b = 0; b < k && first_b; b++) { - first_b = first_b->next; - } - /* all batches merged? */ - if (first_b == NULL) { - break; - } - - /* merge batches */ - bNode *node_a = first_a; - bNode *node_b = first_b; - int a = 0; - int b = 0; - while (a < k && b < k && node_b) { - if (compare_nodes(node_a, node_b) == 0) { - node_a = node_a->next; - a++; - } - else { - bNode *tmp = node_b; - node_b = node_b->next; - b++; - BLI_remlink(&ntree->nodes, tmp); - BLI_insertlinkbefore(&ntree->nodes, node_a, tmp); - } - } - - /* setup first pointers for next batch */ - first_b = node_b; - for (; b < k; b++) { - /* all nodes sorted? */ - if (first_b == NULL) { - break; - } - first_b = first_b->next; - } - first_a = first_b; - } while (first_b); - - k = k << 1; - } -} - -static void do_node_internal_buttons(bContext *C, void *UNUSED(node_v), int event) -{ - if (event == B_NODE_EXEC) { - SpaceNode *snode = CTX_wm_space_node(C); - if (snode && snode->id) { - ED_node_tag_update_id(snode->id); - } - } -} - -static void node_uiblocks_init(const bContext *C, bNodeTree *ntree) -{ - /* add node uiBlocks in drawing order - prevents events going to overlapping nodes */ - - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - /* ui block */ - char uiblockstr[32]; - BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node); - node->block = UI_block_begin(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS); - UI_block_func_handle_set(node->block, do_node_internal_buttons, node); - - /* this cancels events for background nodes */ - UI_block_flag_enable(node->block, UI_BLOCK_CLIP_EVENTS); - } -} - -void node_to_view(const bNode *node, float x, float y, float *rx, float *ry) -{ - nodeToView(node, x, y, rx, ry); - *rx *= UI_DPI_FAC; - *ry *= UI_DPI_FAC; -} - -void node_to_updated_rect(const bNode *node, rctf *r_rect) -{ - node_to_view(node, node->offsetx, node->offsety, &r_rect->xmin, &r_rect->ymax); - node_to_view(node, - node->offsetx + node->width, - node->offsety - node->height, - &r_rect->xmax, - &r_rect->ymin); -} - -void node_from_view(const bNode *node, float x, float y, float *rx, float *ry) -{ - x /= UI_DPI_FAC; - y /= UI_DPI_FAC; - nodeFromView(node, x, y, rx, ry); -} - -/* based on settings in node, sets drawing rect info. each redraw! */ -static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) -{ - PointerRNA nodeptr; - RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); - - /* get "global" coords */ - float locx, locy; - node_to_view(node, 0.0f, 0.0f, &locx, &locy); - float dy = locy; - - /* header */ - dy -= NODE_DY; - - /* little bit space in top */ - if (node->outputs.first) { - dy -= NODE_DYS / 2; - } - - /* output sockets */ - bool add_output_space = false; - - int buty; - LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) { - if (nodeSocketIsHidden(nsock)) { - continue; - } - - PointerRNA sockptr; - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr); - - uiLayout *layout = UI_block_layout(node->block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - locx + NODE_DYS, - dy, - NODE_WIDTH(node) - NODE_DY, - NODE_DY, - 0, - UI_style_get_dpi()); - - if (node->flag & NODE_MUTED) { - uiLayoutSetActive(layout, false); - } - - /* context pointers for current node and socket */ - uiLayoutSetContextPointer(layout, "node", &nodeptr); - uiLayoutSetContextPointer(layout, "socket", &sockptr); - - /* align output buttons to the right */ - uiLayout *row = uiLayoutRow(layout, true); - uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); - const char *socket_label = nodeSocketLabel(nsock); - nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label)); - - UI_block_align_end(node->block); - UI_block_layout_resolve(node->block, NULL, &buty); - - /* ensure minimum socket height in case layout is empty */ - buty = min_ii(buty, dy - NODE_DY); - - nsock->locx = locx + NODE_WIDTH(node); - /* place the socket circle in the middle of the layout */ - nsock->locy = 0.5f * (dy + buty); - - dy = buty; - if (nsock->next) { - dy -= NODE_SOCKDY; - } - - add_output_space = true; - } - - if (add_output_space) { - dy -= NODE_DY / 4; - } - - node->prvr.xmin = locx + NODE_DYS; - node->prvr.xmax = locx + NODE_WIDTH(node) - NODE_DYS; - - /* preview rect? */ - if (node->flag & NODE_PREVIEW) { - float aspect = 1.0f; - - if (node->preview_xsize && node->preview_ysize) { - aspect = (float)node->preview_ysize / (float)node->preview_xsize; - } - - dy -= NODE_DYS / 2; - node->prvr.ymax = dy; - - if (aspect <= 1.0f) { - node->prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY); - } - else { - /* width correction of image */ - /* XXX huh? (ton) */ - float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect; - - node->prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY); - - node->prvr.xmin += 0.5f * dx; - node->prvr.xmax -= 0.5f * dx; - } - - dy = node->prvr.ymin - NODE_DYS / 2; - - /* make sure that maximums are bigger or equal to minimums */ - if (node->prvr.xmax < node->prvr.xmin) { - SWAP(float, node->prvr.xmax, node->prvr.xmin); - } - if (node->prvr.ymax < node->prvr.ymin) { - SWAP(float, node->prvr.ymax, node->prvr.ymin); - } - } - - /* buttons rect? */ - if (node->typeinfo->draw_buttons && (node->flag & NODE_OPTIONS)) { - dy -= NODE_DYS / 2; - - /* set this for uifunc() that don't use layout engine yet */ - node->butr.xmin = 0; - node->butr.xmax = NODE_WIDTH(node) - 2 * NODE_DYS; - node->butr.ymin = 0; - node->butr.ymax = 0; - - uiLayout *layout = UI_block_layout(node->block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - locx + NODE_DYS, - dy, - node->butr.xmax, - 0, - 0, - UI_style_get_dpi()); - - if (node->flag & NODE_MUTED) { - uiLayoutSetActive(layout, false); - } - - uiLayoutSetContextPointer(layout, "node", &nodeptr); - - node->typeinfo->draw_buttons(layout, (bContext *)C, &nodeptr); - - UI_block_align_end(node->block); - UI_block_layout_resolve(node->block, NULL, &buty); - - dy = buty - NODE_DYS / 2; - } - - /* input sockets */ - LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) { - if (nodeSocketIsHidden(nsock)) { - continue; - } - - PointerRNA sockptr; - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr); - - /* Add the half the height of a multi-input socket to cursor Y - * to account for the increased height of the taller sockets. */ - float multi_input_socket_offset = 0.0f; - if (nsock->flag & SOCK_MULTI_INPUT) { - if (nsock->total_inputs > 2) { - multi_input_socket_offset = (nsock->total_inputs - 2) * NODE_MULTI_INPUT_LINK_GAP; - } - } - dy -= multi_input_socket_offset * 0.5f; - - uiLayout *layout = UI_block_layout(node->block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - locx + NODE_DYS, - dy, - NODE_WIDTH(node) - NODE_DY, - NODE_DY, - 0, - UI_style_get_dpi()); - - if (node->flag & NODE_MUTED) { - uiLayoutSetActive(layout, false); - } - - /* context pointers for current node and socket */ - uiLayoutSetContextPointer(layout, "node", &nodeptr); - uiLayoutSetContextPointer(layout, "socket", &sockptr); - - uiLayout *row = uiLayoutRow(layout, true); - - const char *socket_label = nodeSocketLabel(nsock); - nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label)); - - UI_block_align_end(node->block); - UI_block_layout_resolve(node->block, NULL, &buty); - - /* ensure minimum socket height in case layout is empty */ - buty = min_ii(buty, dy - NODE_DY); - - nsock->locx = locx; - /* place the socket circle in the middle of the layout */ - nsock->locy = 0.5f * (dy + buty); - - dy = buty - multi_input_socket_offset * 0.5; - if (nsock->next) { - dy -= NODE_SOCKDY; - } - } - - /* little bit space in end */ - if (node->inputs.first || (node->flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0) { - dy -= NODE_DYS / 2; - } - - node->totr.xmin = locx; - node->totr.xmax = locx + NODE_WIDTH(node); - node->totr.ymax = locy; - node->totr.ymin = min_ff(dy, locy - 2 * NODE_DY); - - /* Set the block bounds to clip mouse events from underlying nodes. - * Add a margin for sockets on each side. - */ - UI_block_bounds_set_explicit(node->block, - node->totr.xmin - NODE_SOCKSIZE, - node->totr.ymin, - node->totr.xmax + NODE_SOCKSIZE, - node->totr.ymax); -} - -/* based on settings in node, sets drawing rect info. each redraw! */ -static void node_update_hidden(bNode *node) -{ - int totin = 0, totout = 0; - - /* get "global" coords */ - float locx, locy; - node_to_view(node, 0.0f, 0.0f, &locx, &locy); - - /* calculate minimal radius */ - LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) { - if (!nodeSocketIsHidden(nsock)) { - totin++; - } - } - LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) { - if (!nodeSocketIsHidden(nsock)) { - totout++; - } - } - - float hiddenrad = HIDDEN_RAD; - float tot = MAX2(totin, totout); - if (tot > 4) { - hiddenrad += 5.0f * (float)(tot - 4); - } - - node->totr.xmin = locx; - node->totr.xmax = locx + max_ff(NODE_WIDTH(node), 2 * hiddenrad); - node->totr.ymax = locy + (hiddenrad - 0.5f * NODE_DY); - node->totr.ymin = node->totr.ymax - 2 * hiddenrad; - - /* output sockets */ - float rad = (float)M_PI / (1.0f + (float)totout); - float drad = rad; - - LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) { - if (!nodeSocketIsHidden(nsock)) { - nsock->locx = node->totr.xmax - hiddenrad + sinf(rad) * hiddenrad; - nsock->locy = node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad; - rad += drad; - } - } - - /* input sockets */ - rad = drad = -(float)M_PI / (1.0f + (float)totin); - - LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) { - if (!nodeSocketIsHidden(nsock)) { - nsock->locx = node->totr.xmin + hiddenrad + sinf(rad) * hiddenrad; - nsock->locy = node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad; - rad += drad; - } - } - - /* Set the block bounds to clip mouse events from underlying nodes. - * Add a margin for sockets on each side. - */ - UI_block_bounds_set_explicit(node->block, - node->totr.xmin - NODE_SOCKSIZE, - node->totr.ymin, - node->totr.xmax + NODE_SOCKSIZE, - node->totr.ymax); -} - -void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node) -{ - if (node->flag & NODE_HIDDEN) { - node_update_hidden(node); - } - else { - node_update_basis(C, ntree, node); - } -} - -int node_select_area_default(bNode *node, int x, int y) -{ - return BLI_rctf_isect_pt(&node->totr, x, y); -} - -int node_tweak_area_default(bNode *node, int x, int y) -{ - return BLI_rctf_isect_pt(&node->totr, x, y); -} - -int node_get_colorid(bNode *node) -{ - switch (node->typeinfo->nclass) { - case NODE_CLASS_INPUT: - return TH_NODE_INPUT; - case NODE_CLASS_OUTPUT: - return (node->flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE; - case NODE_CLASS_CONVERTOR: - return TH_NODE_CONVERTOR; - case NODE_CLASS_OP_COLOR: - return TH_NODE_COLOR; - case NODE_CLASS_OP_VECTOR: - return TH_NODE_VECTOR; - case NODE_CLASS_OP_FILTER: - return TH_NODE_FILTER; - case NODE_CLASS_GROUP: - return TH_NODE_GROUP; - case NODE_CLASS_INTERFACE: - return TH_NODE_INTERFACE; - case NODE_CLASS_MATTE: - return TH_NODE_MATTE; - case NODE_CLASS_DISTORT: - return TH_NODE_DISTORT; - case NODE_CLASS_TEXTURE: - return TH_NODE_TEXTURE; - case NODE_CLASS_SHADER: - return TH_NODE_SHADER; - case NODE_CLASS_SCRIPT: - return TH_NODE_SCRIPT; - case NODE_CLASS_PATTERN: - return TH_NODE_PATTERN; - case NODE_CLASS_LAYOUT: - return TH_NODE_LAYOUT; - case NODE_CLASS_GEOMETRY: - return TH_NODE_GEOMETRY; - case NODE_CLASS_ATTRIBUTE: - return TH_NODE_ATTRIBUTE; - default: - return TH_NODE; - } -} - -/* note: in cmp_util.c is similar code, for node_compo_pass_on() - * the same goes for shader and texture nodes. */ -/* note: in node_edit.c is similar code, for untangle node */ -static void node_draw_mute_line(const View2D *v2d, const SpaceNode *snode, const bNode *node) -{ - GPU_blend(GPU_BLEND_ALPHA); - - LISTBASE_FOREACH (const bNodeLink *, link, &node->internal_links) { - node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1); - } - - GPU_blend(GPU_BLEND_NONE); -} - -/* flags used in gpu_shader_keyframe_diamond_frag.glsl */ -#define MARKER_SHAPE_DIAMOND 0x1 -#define MARKER_SHAPE_SQUARE 0xC -#define MARKER_SHAPE_CIRCLE 0x2 -#define MARKER_SHAPE_INNER_DOT 0x10 - -static void node_socket_draw(const bNodeSocket *sock, - const float color[4], - const float color_outline[4], - float size, - int locx, - int locy, - uint pos_id, - uint col_id, - uint shape_id, - uint size_id, - uint outline_col_id) -{ - int flags; - - /* sets shape flags */ - switch (sock->display_shape) { - case SOCK_DISPLAY_SHAPE_DIAMOND: - case SOCK_DISPLAY_SHAPE_DIAMOND_DOT: - flags = MARKER_SHAPE_DIAMOND; - break; - case SOCK_DISPLAY_SHAPE_SQUARE: - case SOCK_DISPLAY_SHAPE_SQUARE_DOT: - flags = MARKER_SHAPE_SQUARE; - break; - default: - case SOCK_DISPLAY_SHAPE_CIRCLE: - case SOCK_DISPLAY_SHAPE_CIRCLE_DOT: - flags = MARKER_SHAPE_CIRCLE; - break; - } - - if (ELEM(sock->display_shape, - SOCK_DISPLAY_SHAPE_DIAMOND_DOT, - SOCK_DISPLAY_SHAPE_SQUARE_DOT, - SOCK_DISPLAY_SHAPE_CIRCLE_DOT)) { - flags |= MARKER_SHAPE_INNER_DOT; - } - - immAttr4fv(col_id, color); - immAttr1u(shape_id, flags); - immAttr1f(size_id, size); - immAttr4fv(outline_col_id, color_outline); - immVertex2f(pos_id, locx, locy); -} - -static void node_socket_draw_multi_input(const float color[4], - const float color_outline[4], - const float width, - const float height, - const int locx, - const int locy) -{ - const float outline_width = 1.0f; - /* UI_draw_roundbox draws the outline on the outer side, so compensate for the outline width. */ - const rctf rect = { - .xmin = locx - width + outline_width * 0.5f, - .xmax = locx + width - outline_width * 0.5f, - .ymin = locy - height + outline_width * 0.5f, - .ymax = locy + height - outline_width * 0.5f, - }; - - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_4fv_ex( - &rect, color, NULL, 1.0f, color_outline, outline_width, width - outline_width * 0.5f); -} - -static void node_socket_outline_color_get(bool selected, float r_outline_color[4]) -{ - if (selected) { - UI_GetThemeColor4fv(TH_TEXT_HI, r_outline_color); - r_outline_color[3] = 0.9f; - } - else { - copy_v4_fl(r_outline_color, 0.0f); - r_outline_color[3] = 0.6f; - } -} - -/* Usual convention here would be node_socket_get_color(), but that's already used (for setting a - * color property socket). */ -void node_socket_color_get( - bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4]) -{ - PointerRNA ptr; - BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node)); - RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); - - sock->typeinfo->draw_color(C, &ptr, node_ptr, r_color); - - bNode *node = node_ptr->data; - if (node->flag & NODE_MUTED) { - r_color[3] *= 0.25f; - } -} - -static void node_socket_draw_nested(const bContext *C, - bNodeTree *ntree, - PointerRNA *node_ptr, - bNodeSocket *sock, - uint pos_id, - uint col_id, - uint shape_id, - uint size_id, - uint outline_col_id, - float size, - bool selected) -{ - float color[4]; - float outline_color[4]; - - node_socket_color_get((bContext *)C, ntree, node_ptr, sock, color); - node_socket_outline_color_get(selected, outline_color); - - node_socket_draw(sock, - color, - outline_color, - size, - sock->locx, - sock->locy, - pos_id, - col_id, - shape_id, - size_id, - outline_col_id); -} - -/** - * Draw a single node socket at default size. - * \note this is only called from external code, internally #node_socket_draw_nested() is used for - * optimized drawing of multiple/all sockets of a node. - */ -void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale) -{ - const float size = 2.25f * NODE_SOCKSIZE * scale; - rcti draw_rect = *rect; - float outline_color[4] = {0}; - - node_socket_outline_color_get(sock->flag & SELECT, outline_color); - - BLI_rcti_resize(&draw_rect, size, size); - - GPUVertFormat *format = immVertexFormat(); - uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); - uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - uint outline_col_id = GPU_vertformat_attr_add( - format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - - eGPUBlend state = GPU_blend_get(); - GPU_blend(GPU_BLEND_ALPHA); - GPU_program_point_size(true); - - immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); - immUniform1f("outline_scale", 0.7f); - immUniform2f("ViewportSize", -1.0f, -1.0f); - - /* Single point */ - immBegin(GPU_PRIM_POINTS, 1); - node_socket_draw(sock, - color, - outline_color, - BLI_rcti_size_y(&draw_rect), - BLI_rcti_cent_x(&draw_rect), - BLI_rcti_cent_y(&draw_rect), - pos_id, - col_id, - shape_id, - size_id, - outline_col_id); - immEnd(); - - immUnbindProgram(); - GPU_program_point_size(false); - - /* Restore. */ - GPU_blend(state); -} - -/* ************** Socket callbacks *********** */ - -static void node_draw_preview_background(rctf *rect) -{ - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_CHECKER); - - /* Drawing the checkerboard. */ - const float checker_dark = UI_ALPHA_CHECKER_DARK / 255.0f; - const float checker_light = UI_ALPHA_CHECKER_LIGHT / 255.0f; - immUniform4f("color1", checker_dark, checker_dark, checker_dark, 1.0f); - immUniform4f("color2", checker_light, checker_light, checker_light, 1.0f); - immUniform1i("size", 8); - immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); - immUnbindProgram(); -} - -/* not a callback */ -static void node_draw_preview(bNodePreview *preview, rctf *prv) -{ - float xrect = BLI_rctf_size_x(prv); - float yrect = BLI_rctf_size_y(prv); - float xscale = xrect / ((float)preview->xsize); - float yscale = yrect / ((float)preview->ysize); - float scale; - - /* uniform scale and offset */ - rctf draw_rect = *prv; - if (xscale < yscale) { - float offset = 0.5f * (yrect - ((float)preview->ysize) * xscale); - draw_rect.ymin += offset; - draw_rect.ymax -= offset; - scale = xscale; - } - else { - float offset = 0.5f * (xrect - ((float)preview->xsize) * yscale); - draw_rect.xmin += offset; - draw_rect.xmax -= offset; - scale = yscale; - } - - node_draw_preview_background(&draw_rect); - - GPU_blend(GPU_BLEND_ALPHA); - /* premul graphics */ - GPU_blend(GPU_BLEND_ALPHA); - - IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex(&state, - draw_rect.xmin, - draw_rect.ymin, - preview->xsize, - preview->ysize, - GPU_RGBA8, - true, - preview->rect, - scale, - scale, - NULL); - - GPU_blend(GPU_BLEND_NONE); - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColorShadeAlpha(TH_BACK, -15, +100); - imm_draw_box_wire_2d(pos, draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax); - immUnbindProgram(); -} - -/* common handle function for operator buttons that need to select the node first */ -static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv) -{ - bNode *node = (bNode *)node_argv; - const char *opname = (const char *)op_argv; - - /* select & activate only the button's node */ - node_select_single(C, node); - - WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, NULL); -} - -void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha) -{ - const rctf *rct = &node->totr; - UI_draw_roundbox_corner_set(UI_CNR_ALL); - ui_draw_dropshadow(rct, radius, snode->runtime->aspect, alpha, node->flag & SELECT); -} - -void node_draw_sockets(const View2D *v2d, - const bContext *C, - bNodeTree *ntree, - bNode *node, - bool draw_outputs, - bool select_all) -{ - const uint total_input_len = BLI_listbase_count(&node->inputs); - const uint total_output_len = BLI_listbase_count(&node->outputs); - - if (total_input_len + total_output_len == 0) { - return; - } - - PointerRNA node_ptr; - RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); - - bool selected = false; - - GPUVertFormat *format = immVertexFormat(); - uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); - uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - uint outline_col_id = GPU_vertformat_attr_add( - format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - - GPU_blend(GPU_BLEND_ALPHA); - GPU_program_point_size(true); - immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); - immUniform1f("outline_scale", 0.7f); - immUniform2f("ViewportSize", -1.0f, -1.0f); - - /* set handle size */ - float scale; - UI_view2d_scale_get(v2d, &scale, NULL); - scale *= 2.25f * NODE_SOCKSIZE; - - if (!select_all) { - immBeginAtMost(GPU_PRIM_POINTS, total_input_len + total_output_len); - } - - /* socket inputs */ - short selected_input_len = 0; - LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - if (nodeSocketIsHidden(sock)) { - continue; - } - if (select_all || (sock->flag & SELECT)) { - selected_input_len++; - continue; - } - /* Don't draw multi-input sockets here since they are drawn in a different batch. */ - if (sock->flag & SOCK_MULTI_INPUT) { - continue; - } - - node_socket_draw_nested(C, - ntree, - &node_ptr, - sock, - pos_id, - col_id, - shape_id, - size_id, - outline_col_id, - scale, - selected); - } - - /* socket outputs */ - short selected_output_len = 0; - if (draw_outputs) { - LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { - if (nodeSocketIsHidden(sock)) { - continue; - } - if (select_all || (sock->flag & SELECT)) { - selected_output_len++; - continue; - } - - node_socket_draw_nested(C, - ntree, - &node_ptr, - sock, - pos_id, - col_id, - shape_id, - size_id, - outline_col_id, - scale, - selected); - } - } - - if (!select_all) { - immEnd(); - } - - /* go back and draw selected sockets */ - if (selected_input_len + selected_output_len > 0) { - /* outline for selected sockets */ - - selected = true; - - immBegin(GPU_PRIM_POINTS, selected_input_len + selected_output_len); - - if (selected_input_len) { - /* socket inputs */ - LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - if (nodeSocketIsHidden(sock)) { - continue; - } - if (select_all || (sock->flag & SELECT)) { - node_socket_draw_nested(C, - ntree, - &node_ptr, - sock, - pos_id, - col_id, - shape_id, - size_id, - outline_col_id, - scale, - selected); - if (--selected_input_len == 0) { - break; /* stop as soon as last one is drawn */ - } - } - } - } - - if (selected_output_len) { - /* socket outputs */ - LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { - if (nodeSocketIsHidden(sock)) { - continue; - } - if (select_all || (sock->flag & SELECT)) { - node_socket_draw_nested(C, - ntree, - &node_ptr, - sock, - pos_id, - col_id, - shape_id, - size_id, - outline_col_id, - scale, - selected); - if (--selected_output_len == 0) { - break; /* stop as soon as last one is drawn */ - } - } - } - } - - immEnd(); - } - - immUnbindProgram(); - - GPU_program_point_size(false); - GPU_blend(GPU_BLEND_NONE); - - /* Draw multi-input sockets after the others because they are drawn with `UI_draw_roundbox` - * rather than with `GL_POINT`. */ - LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { - if (nodeSocketIsHidden(socket)) { - continue; - } - if (!(socket->flag & SOCK_MULTI_INPUT)) { - continue; - } - - const bool is_node_hidden = (node->flag & NODE_HIDDEN); - const float width = NODE_SOCKSIZE; - float height = is_node_hidden ? width : node_socket_calculate_height(socket) - width; - - float color[4]; - float outline_color[4]; - node_socket_color_get((bContext *)C, ntree, &node_ptr, socket, color); - node_socket_outline_color_get(selected, outline_color); - - node_socket_draw_multi_input(color, outline_color, width, height, socket->locx, socket->locy); - } -} - -static void node_draw_basis(const bContext *C, - const View2D *v2d, - const SpaceNode *snode, - bNodeTree *ntree, - bNode *node, - bNodeInstanceKey key) -{ - /* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */ - float iconbutw = 0.8f * UI_UNIT_X; - - /* skip if out of view */ - if (BLI_rctf_isect(&node->totr, &v2d->cur, NULL) == false) { - UI_block_end(C, node->block); - node->block = NULL; - return; - } - - /* shadow */ - node_draw_shadow(snode, node, BASIS_RAD, 1.0f); - - float color[4]; - int color_id = node_get_colorid(node); - if (node->flag & NODE_MUTED) { - /* Muted nodes are semi-transparent and colorless. */ - UI_GetThemeColor3fv(TH_NODE, color); - color[3] = 0.25f; - } - else { - /* Opaque headers for regular nodes. */ - UI_GetThemeColor3fv(color_id, color); - color[3] = 1.0f; - } - - GPU_line_width(1.0f); - - rctf *rct = &node->totr; - UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT); - UI_draw_roundbox_aa( - &(const rctf){ - .xmin = rct->xmin, - .xmax = rct->xmax, - .ymin = rct->ymax - NODE_DY, - .ymax = rct->ymax, - }, - true, - BASIS_RAD, - color); - - /* show/hide icons */ - float iconofs = rct->xmax - 0.35f * U.widget_unit; - - /* preview */ - if (node->typeinfo->flag & NODE_PREVIEW) { - iconofs -= iconbutw; - UI_block_emboss_set(node->block, UI_EMBOSS_NONE); - uiBut *but = uiDefIconBut(node->block, - UI_BTYPE_BUT_TOGGLE, - B_REDR, - ICON_MATERIAL, - iconofs, - rct->ymax - NODE_DY, - iconbutw, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - ""); - UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_preview_toggle"); - /* XXX this does not work when node is activated and the operator called right afterwards, - * since active ID is not updated yet (needs to process the notifier). - * This can only work as visual indicator! - */ - // if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))) - // UI_but_flag_enable(but, UI_BUT_DISABLED); - UI_block_emboss_set(node->block, UI_EMBOSS); - } - /* group edit */ - if (node->type == NODE_GROUP) { - iconofs -= iconbutw; - UI_block_emboss_set(node->block, UI_EMBOSS_NONE); - uiBut *but = uiDefIconBut(node->block, - UI_BTYPE_BUT_TOGGLE, - B_REDR, - ICON_NODETREE, - iconofs, - rct->ymax - NODE_DY, - iconbutw, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - ""); - UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_group_edit"); - UI_block_emboss_set(node->block, UI_EMBOSS); - } - if (node->type == NODE_CUSTOM && node->typeinfo->ui_icon != ICON_NONE) { - iconofs -= iconbutw; - UI_block_emboss_set(node->block, UI_EMBOSS_NONE); - uiDefIconBut(node->block, - UI_BTYPE_BUT, - 0, - node->typeinfo->ui_icon, - iconofs, - rct->ymax - NODE_DY, - iconbutw, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - ""); - UI_block_emboss_set(node->block, UI_EMBOSS); - } - - /* title */ - if (node->flag & SELECT) { - UI_GetThemeColor4fv(TH_SELECT, color); - } - else { - UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color); - } - - /* open/close entirely? */ - { - int but_size = U.widget_unit * 0.8f; - /* XXX button uses a custom triangle draw below, so make it invisible without icon */ - UI_block_emboss_set(node->block, UI_EMBOSS_NONE); - uiBut *but = uiDefBut(node->block, - UI_BTYPE_BUT_TOGGLE, - B_REDR, - "", - rct->xmin + 0.35f * U.widget_unit, - rct->ymax - NODE_DY / 2.2f - but_size / 2, - but_size, - but_size, - NULL, - 0, - 0, - 0, - 0, - ""); - UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle"); - UI_block_emboss_set(node->block, UI_EMBOSS); - - UI_GetThemeColor4fv(TH_TEXT, color); - /* custom draw function for this button */ - UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, rct->ymax - NODE_DY / 2.2f, 'v', color); - } - - char showname[128]; /* 128 used below */ - nodeLabel(ntree, node, showname, sizeof(showname)); - - uiBut *but = uiDefBut(node->block, - UI_BTYPE_LABEL, - 0, - showname, - (int)(rct->xmin + NODE_MARGIN_X), - (int)(rct->ymax - NODE_DY), - (short)(iconofs - rct->xmin - (18.0f * U.dpi_fac)), - (short)NODE_DY, - NULL, - 0, - 0, - 0, - 0, - ""); - if (node->flag & NODE_MUTED) { - UI_but_flag_enable(but, UI_BUT_INACTIVE); - } - - /* body */ - if (nodeTypeUndefined(node)) { - /* use warning color to indicate undefined types */ - UI_GetThemeColor4fv(TH_REDALERT, color); - } - else if (node->flag & NODE_MUTED) { - /* Muted nodes are semi-transparent and colorless. */ - UI_GetThemeColor4fv(TH_NODE, color); - } - else if (node->flag & NODE_CUSTOM_COLOR) { - rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f); - } - else { - UI_GetThemeColor4fv(TH_NODE, color); - } - - if (node->flag & NODE_MUTED) { - color[3] = 0.5f; - } - - UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT); - UI_draw_roundbox_aa( - &(const rctf){ - .xmin = rct->xmin, - .xmax = rct->xmax, - .ymin = rct->ymin, - .ymax = rct->ymax - NODE_DY, - }, - true, - BASIS_RAD, - color); - - /* outline active and selected emphasis */ - if (node->flag & SELECT) { - UI_GetThemeColorShadeAlpha4fv( - (node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color); - - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa( - &(const rctf){ - .xmin = rct->xmin, - .xmax = rct->xmax, - .ymin = rct->ymin, - .ymax = rct->ymax, - }, - false, - BASIS_RAD, - color); - } - - /* disable lines */ - if (node->flag & NODE_MUTED) { - node_draw_mute_line(v2d, snode, node); - } - - node_draw_sockets(v2d, C, ntree, node, true, false); - - /* preview */ - bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data; - if (node->flag & NODE_PREVIEW && previews) { - bNodePreview *preview = BKE_node_instance_hash_lookup(previews, key); - if (preview && (preview->xsize && preview->ysize)) { - if (preview->rect && !BLI_rctf_is_empty(&node->prvr)) { - node_draw_preview(preview, &node->prvr); - } - } - } - - UI_block_end(C, node->block); - UI_block_draw(C, node->block); - node->block = NULL; -} - -static void node_draw_hidden(const bContext *C, - const View2D *v2d, - const SpaceNode *snode, - bNodeTree *ntree, - bNode *node, - bNodeInstanceKey UNUSED(key)) -{ - rctf *rct = &node->totr; - float centy = BLI_rctf_cent_y(rct); - float hiddenrad = BLI_rctf_size_y(rct) / 2.0f; - - float scale; - UI_view2d_scale_get(v2d, &scale, NULL); - - /* shadow */ - node_draw_shadow(snode, node, hiddenrad, 1.0f); - - /* body */ - float color[4]; - int color_id = node_get_colorid(node); - if (node->flag & NODE_MUTED) { - /* Muted nodes are semi-transparent and colorless. */ - UI_GetThemeColor4fv(TH_NODE, color); - color[3] = 0.25f; - } - else { - UI_GetThemeColor4fv(color_id, color); - } - - UI_draw_roundbox_aa(rct, true, hiddenrad, color); - - /* outline active and selected emphasis */ - if (node->flag & SELECT) { - UI_GetThemeColorShadeAlpha4fv( - (node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color); - - UI_draw_roundbox_aa(rct, false, hiddenrad, color); - } - - /* custom color inline */ - if (node->flag & NODE_CUSTOM_COLOR) { - GPU_blend(GPU_BLEND_ALPHA); - GPU_line_smooth(true); - - UI_draw_roundbox_3fv_alpha( - &(const rctf){ - .xmin = rct->xmin + 1, - .xmax = rct->xmax - 1, - .ymin = rct->ymin + 1, - .ymax = rct->ymax - 1, - }, - false, - hiddenrad, - node->color, - 1.0f); - - GPU_line_smooth(false); - GPU_blend(GPU_BLEND_NONE); - } - - /* title */ - if (node->flag & SELECT) { - UI_GetThemeColor4fv(TH_SELECT, color); - } - else { - UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color); - } - - /* open entirely icon */ - { - int but_size = U.widget_unit * 0.8f; - /* XXX button uses a custom triangle draw below, so make it invisible without icon */ - UI_block_emboss_set(node->block, UI_EMBOSS_NONE); - uiBut *but = uiDefBut(node->block, - UI_BTYPE_BUT_TOGGLE, - B_REDR, - "", - rct->xmin + 0.35f * U.widget_unit, - centy - but_size / 2, - but_size, - but_size, - NULL, - 0, - 0, - 0, - 0, - ""); - UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle"); - UI_block_emboss_set(node->block, UI_EMBOSS); - - UI_GetThemeColor4fv(TH_TEXT, color); - /* custom draw function for this button */ - UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, centy, 'h', color); - } - - /* disable lines */ - if (node->flag & NODE_MUTED) { - node_draw_mute_line(v2d, snode, node); - } - - char showname[128]; /* 128 is used below */ - nodeLabel(ntree, node, showname, sizeof(showname)); - - /* XXX - don't print into self! */ - // if (node->flag & NODE_MUTED) - // BLI_snprintf(showname, sizeof(showname), "[%s]", showname); - - uiBut *but = uiDefBut(node->block, - UI_BTYPE_LABEL, - 0, - showname, - round_fl_to_int(rct->xmin + NODE_MARGIN_X), - round_fl_to_int(centy - NODE_DY * 0.5f), - (short)(BLI_rctf_size_x(rct) - ((18.0f + 12.0f) * U.dpi_fac)), - (short)NODE_DY, - NULL, - 0, - 0, - 0, - 0, - ""); - if (node->flag & NODE_MUTED) { - UI_but_flag_enable(but, UI_BUT_INACTIVE); - } - - /* scale widget thing */ - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - immUniformThemeColorShade(color_id, -10); - float dx = 10.0f; - - immBegin(GPU_PRIM_LINES, 4); - immVertex2f(pos, rct->xmax - dx, centy - 4.0f); - immVertex2f(pos, rct->xmax - dx, centy + 4.0f); - - immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy - 4.0f); - immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy + 4.0f); - immEnd(); - - immUniformThemeColorShade(color_id, 30); - dx -= snode->runtime->aspect; - - immBegin(GPU_PRIM_LINES, 4); - immVertex2f(pos, rct->xmax - dx, centy - 4.0f); - immVertex2f(pos, rct->xmax - dx, centy + 4.0f); - - immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy - 4.0f); - immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy + 4.0f); - immEnd(); - - immUnbindProgram(); - - node_draw_sockets(v2d, C, ntree, node, true, false); - - UI_block_end(C, node->block); - UI_block_draw(C, node->block); - node->block = NULL; -} - -int node_get_resize_cursor(int directions) -{ - if (directions == 0) { - return WM_CURSOR_DEFAULT; - } - if ((directions & ~(NODE_RESIZE_TOP | NODE_RESIZE_BOTTOM)) == 0) { - return WM_CURSOR_Y_MOVE; - } - if ((directions & ~(NODE_RESIZE_RIGHT | NODE_RESIZE_LEFT)) == 0) { - return WM_CURSOR_X_MOVE; - } - return WM_CURSOR_EDIT; -} - -void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2]) -{ - bNodeTree *ntree = snode->edittree; - bNode *node; - bNodeSocket *sock; - int wmcursor = WM_CURSOR_DEFAULT; - - if (ntree) { - if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) { - /* pass */ - } - else { - /* check nodes front to back */ - for (node = ntree->nodes.last; node; node = node->prev) { - if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) { - break; /* first hit on node stops */ - } - } - if (node) { - int dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]); - wmcursor = node_get_resize_cursor(dir); - } - } - } - - WM_cursor_set(win, wmcursor); -} - -void node_draw_default(const bContext *C, - ARegion *region, - SpaceNode *snode, - bNodeTree *ntree, - bNode *node, - bNodeInstanceKey key) -{ - const View2D *v2d = ®ion->v2d; - if (node->flag & NODE_HIDDEN) { - node_draw_hidden(C, v2d, snode, ntree, node, key); - } - else { - node_draw_basis(C, v2d, snode, ntree, node, key); - } -} - -static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) -{ - if (node->typeinfo->draw_nodetype_prepare) { - node->typeinfo->draw_nodetype_prepare(C, ntree, node); - } -} - -static void count_mutli_input_socket_links(bNodeTree *ntree, SpaceNode *snode) -{ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - LISTBASE_FOREACH (struct bNodeSocket *, socket, &node->inputs) { - if (socket->flag & SOCK_MULTI_INPUT) { - socket->total_inputs = 0; - LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { - if (link->tosock == socket) { - socket->total_inputs++; - } - } - /* Count temporary links going into this socket. */ - LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - if (link->tosock == socket) { - socket->total_inputs++; - } - } - } - } - } - } -} - -void node_update_nodetree(const bContext *C, bNodeTree *ntree) -{ - /* make sure socket "used" tags are correct, for displaying value buttons */ - SpaceNode *snode = CTX_wm_space_node(C); - ntreeTagUsedSockets(ntree); - - count_mutli_input_socket_links(ntree, snode); - - /* update nodes front to back, so children sizes get updated before parents */ - LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) { - node_update(C, ntree, node); - } -} - -static int compare_link_by_angle_to_node(const void *a, const void *b) -{ - const bNodeLink *link_a = *(const bNodeLink **)a; - const bNodeLink *link_b = *(const bNodeLink **)b; - - BLI_assert(link_a->tosock == link_b->tosock); - const float socket_location[2] = {link_a->tosock->locx, link_a->tosock->locy}; - const float up_direction[2] = {0.0f, 1.0f}; - - float delta_a[2] = {link_a->fromsock->locx - socket_location[0], - link_a->fromsock->locy - socket_location[1]}; - normalize_v2(delta_a); - const float angle_a = angle_normalized_v2v2(up_direction, delta_a); - - float delta_b[2] = {link_b->fromsock->locx - socket_location[0], - link_b->fromsock->locy - socket_location[1]}; - normalize_v2(delta_b); - const float angle_b = angle_normalized_v2v2(up_direction, delta_b); - - return angle_a < angle_b ? 1 : -1; -} - -static void node_draw(const bContext *C, - ARegion *region, - SpaceNode *snode, - bNodeTree *ntree, - bNode *node, - bNodeInstanceKey key) -{ - if (node->typeinfo->draw_nodetype) { - node->typeinfo->draw_nodetype(C, region, snode, ntree, node, key); - } -} - -#define USE_DRAW_TOT_UPDATE - -/** - * Automatically sort the input links to multi-input sockets to avoid crossing noodles. - */ -static void sort_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode) -{ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { - if (socket->flag & SOCK_MULTI_INPUT) { - /* The total is calculated in #node_update_nodetree, which runs before this draw step. */ - const int total_inputs = socket->total_inputs; - bNodeLink **input_links = MEM_malloc_arrayN(total_inputs, sizeof(bNodeLink *), __func__); - - int index = 0; - LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { - if (link->tosock == socket) { - input_links[index] = (bNodeLink *)link; - index++; - } - } - LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - if (link->tosock == socket) { - input_links[index] = (bNodeLink *)link; - index++; - } - } - } - - qsort(input_links, total_inputs, sizeof(bNodeLink *), compare_link_by_angle_to_node); - for (int i = 0; i < total_inputs; i++) { - input_links[i]->multi_input_socket_index = i; - } - - MEM_freeN(input_links); - } - } - } -} - -void node_draw_nodetree(const bContext *C, - ARegion *region, - SpaceNode *snode, - bNodeTree *ntree, - bNodeInstanceKey parent_key) -{ - if (ntree == NULL) { - return; /* groups... */ - } - -#ifdef USE_DRAW_TOT_UPDATE - if (ntree->nodes.first) { - BLI_rctf_init_minmax(®ion->v2d.tot); - } -#endif - - /* draw background nodes, last nodes in front */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { -#ifdef USE_DRAW_TOT_UPDATE - /* unrelated to background nodes, update the v2d->tot, - * can be anywhere before we draw the scroll bars */ - BLI_rctf_union(®ion->v2d.tot, &node->totr); -#endif - - if (!(node->flag & NODE_BACKGROUND)) { - continue; - } - - bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); - node_draw(C, region, snode, ntree, node, key); - } - - /* node lines */ - GPU_blend(GPU_BLEND_ALPHA); - nodelink_batch_start(snode); - - sort_multi_input_socket_links(ntree, snode); - - LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { - if (!nodeLinkIsHidden(link)) { - node_draw_link(®ion->v2d, snode, link); - } - } - nodelink_batch_end(snode); - GPU_blend(GPU_BLEND_NONE); - - /* draw foreground nodes, last nodes in front */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->flag & NODE_BACKGROUND) { - continue; - } - - bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); - node_draw(C, region, snode, ntree, node, key); - } -} - -/* draw tree path info in lower left corner */ -static void draw_tree_path(SpaceNode *snode) -{ - char info[256]; - - ED_node_tree_path_get_fixedbuf(snode, info, sizeof(info)); - - UI_FontThemeColor(BLF_default(), TH_TEXT_HI); - BLF_draw_default(1.5f * UI_UNIT_X, 1.5f * UI_UNIT_Y, 0.0f, info, sizeof(info)); -} - -static void snode_setup_v2d(SpaceNode *snode, ARegion *region, const float center[2]) -{ - View2D *v2d = ®ion->v2d; - - /* shift view to node tree center */ - UI_view2d_center_set(v2d, center[0], center[1]); - UI_view2d_view_ortho(v2d); - - /* aspect+font, set each time */ - snode->runtime->aspect = BLI_rctf_size_x(&v2d->cur) / (float)region->winx; - // XXX snode->curfont = uiSetCurFont_ext(snode->aspect); -} - -static void draw_nodetree(const bContext *C, - ARegion *region, - bNodeTree *ntree, - bNodeInstanceKey parent_key) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - node_uiblocks_init(C, ntree); - - node_update_nodetree(C, ntree); - node_draw_nodetree(C, region, snode, ntree, parent_key); -} - -/* shade the parent node group and add a uiBlock to clip mouse events */ -static void draw_group_overlay(const bContext *C, ARegion *region) -{ - const View2D *v2d = ®ion->v2d; - const rctf rect = v2d->cur; - float color[4]; - - /* shade node groups to separate them visually */ - GPU_blend(GPU_BLEND_ALPHA); - - UI_GetThemeColorShadeAlpha4fv(TH_NODE_GROUP, 0, 0, color); - UI_draw_roundbox_corner_set(UI_CNR_NONE); - UI_draw_roundbox_4fv(&rect, true, 0, color); - GPU_blend(GPU_BLEND_NONE); - - /* set the block bounds to clip mouse events from underlying nodes */ - uiBlock *block = UI_block_begin(C, region, "node tree bounds block", UI_EMBOSS); - UI_block_bounds_set_explicit(block, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - UI_block_flag_enable(block, UI_BLOCK_CLIP_EVENTS); - UI_block_end(C, block); -} - -void node_draw_space(const bContext *C, ARegion *region) -{ - wmWindow *win = CTX_wm_window(C); - SpaceNode *snode = CTX_wm_space_node(C); - View2D *v2d = ®ion->v2d; - - /* Setup offscreen buffers. */ - GPUViewport *viewport = WM_draw_region_get_viewport(region); - - GPUFrameBuffer *framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(viewport); - GPU_framebuffer_bind_no_srgb(framebuffer_overlay); - - UI_view2d_view_ortho(v2d); - UI_ThemeClearColor(TH_BACK); - GPU_depth_test(GPU_DEPTH_NONE); - GPU_scissor_test(true); - - /* XXX snode->runtime->cursor set in coordspace for placing new nodes, used for drawing noodles - * too */ - UI_view2d_region_to_view(®ion->v2d, - win->eventstate->x - region->winrct.xmin, - win->eventstate->y - region->winrct.ymin, - &snode->runtime->cursor[0], - &snode->runtime->cursor[1]); - snode->runtime->cursor[0] /= UI_DPI_FAC; - snode->runtime->cursor[1] /= UI_DPI_FAC; - - int grid_levels = UI_GetThemeValueType(TH_NODE_GRID_LEVELS, SPACE_NODE); - - ED_region_draw_cb_draw(C, region, REGION_DRAW_PRE_VIEW); - - /* only set once */ - GPU_blend(GPU_BLEND_ALPHA); - - /* nodes */ - snode_set_context(C); - - /* draw parent node trees */ - if (snode->treepath.last) { - static const int max_depth = 2; - - bNodeTreePath *path = snode->treepath.last; - - /* update tree path name (drawn in the bottom left) */ - ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id : - snode->id; - - if (name_id && UNLIKELY(!STREQ(path->node_name, name_id->name + 2))) { - BLI_strncpy(path->node_name, name_id->name + 2, sizeof(path->node_name)); - } - - /* current View2D center, will be set temporarily for parent node trees */ - float center[2]; - UI_view2d_center_get(v2d, ¢er[0], ¢er[1]); - - /* store new view center in path and current edittree */ - copy_v2_v2(path->view_center, center); - if (snode->edittree) { - copy_v2_v2(snode->edittree->view_center, center); - } - - int depth = 0; - while (path->prev && depth < max_depth) { - path = path->prev; - depth++; - } - - /* parent node trees in the background */ - for (int curdepth = depth; curdepth > 0; path = path->next, curdepth--) { - bNodeTree *ntree = path->nodetree; - if (ntree) { - snode_setup_v2d(snode, region, path->view_center); - - draw_nodetree(C, region, ntree, path->parent_key); - - draw_group_overlay(C, region); - } - } - - /* top-level edit tree */ - bNodeTree *ntree = path->nodetree; - if (ntree) { - snode_setup_v2d(snode, region, center); - - /* grid, uses theme color based on node path depth */ - UI_view2d_multi_grid_draw(v2d, - (depth > 0 ? TH_NODE_GROUP : TH_GRID), - ED_node_grid_size(), - NODE_GRID_STEPS, - grid_levels); - - /* backdrop */ - draw_nodespace_back_pix(C, region, snode, path->parent_key); - - { - float original_proj[4][4]; - GPU_matrix_projection_get(original_proj); - - GPU_matrix_push(); - GPU_matrix_identity_set(); - - wmOrtho2_pixelspace(region->winx, region->winy); - - WM_gizmomap_draw(region->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D); - - GPU_matrix_pop(); - GPU_matrix_projection_set(original_proj); - } - - draw_nodetree(C, region, ntree, path->parent_key); - } - - /* temporary links */ - GPU_blend(GPU_BLEND_ALPHA); - GPU_line_smooth(true); - LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - node_draw_link(v2d, snode, (bNodeLink *)linkdata->data); - } - } - GPU_line_smooth(false); - GPU_blend(GPU_BLEND_NONE); - - if (snode->flag & SNODE_SHOW_GPENCIL) { - /* draw grease-pencil ('canvas' strokes) */ - ED_annotation_draw_view2d(C, true); - } - } - else { - /* default grid */ - UI_view2d_multi_grid_draw(v2d, TH_GRID, ED_node_grid_size(), NODE_GRID_STEPS, grid_levels); - - /* backdrop */ - draw_nodespace_back_pix(C, region, snode, NODE_INSTANCE_KEY_NONE); - } - - ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW); - - /* reset view matrix */ - UI_view2d_view_restore(C); - - if (snode->treepath.last) { - if (snode->flag & SNODE_SHOW_GPENCIL) { - /* Draw grease-pencil (screen strokes, and also paint-buffer). */ - ED_annotation_draw_view2d(C, false); - } - } - - /* tree path info */ - draw_tree_path(snode); - - /* scrollers */ - UI_view2d_scrollers_draw(v2d, NULL); -} |