1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup spnode
22  * \brief higher level node drawing for the node editor.
23  */
24 
25 #include "DNA_light_types.h"
26 #include "DNA_linestyle_types.h"
27 #include "DNA_material_types.h"
28 #include "DNA_node_types.h"
29 #include "DNA_screen_types.h"
30 #include "DNA_space_types.h"
31 #include "DNA_texture_types.h"
32 #include "DNA_world_types.h"
33 
34 #include "BLI_blenlib.h"
35 #include "BLI_math.h"
36 
37 #include "BLT_translation.h"
38 
39 #include "BKE_context.h"
40 #include "BKE_lib_id.h"
41 #include "BKE_main.h"
42 #include "BKE_node.h"
43 
44 #include "DEG_depsgraph.h"
45 
46 #include "BLF_api.h"
47 
48 #include "BIF_glutil.h"
49 
50 #include "GPU_framebuffer.h"
51 #include "GPU_immediate.h"
52 #include "GPU_immediate_util.h"
53 #include "GPU_matrix.h"
54 #include "GPU_state.h"
55 #include "GPU_viewport.h"
56 
57 #include "WM_api.h"
58 #include "WM_types.h"
59 
60 #include "ED_gpencil.h"
61 #include "ED_node.h"
62 #include "ED_space_api.h"
63 
64 #include "UI_resources.h"
65 #include "UI_view2d.h"
66 
67 #include "RNA_access.h"
68 
69 #include "node_intern.h" /* own include */
70 
71 #ifdef WITH_COMPOSITOR
72 #  include "COM_compositor.h"
73 #endif
74 
75 /* XXX interface.h */
76 extern void ui_draw_dropshadow(
77     const rctf *rct, float radius, float aspect, float alpha, int select);
78 
ED_node_grid_size(void)79 float ED_node_grid_size(void)
80 {
81   return U.widget_unit;
82 }
83 
ED_node_tree_update(const bContext * C)84 void ED_node_tree_update(const bContext *C)
85 {
86   SpaceNode *snode = CTX_wm_space_node(C);
87   if (snode) {
88     snode_set_context(C);
89 
90     id_us_ensure_real(&snode->nodetree->id);
91   }
92 }
93 
94 /* id is supposed to contain a node tree */
node_tree_from_ID(ID * id)95 static bNodeTree *node_tree_from_ID(ID *id)
96 {
97   if (id) {
98     if (GS(id->name) == ID_NT) {
99       return (bNodeTree *)id;
100     }
101     return ntreeFromID(id);
102   }
103 
104   return NULL;
105 }
106 
ED_node_tag_update_id(ID * id)107 void ED_node_tag_update_id(ID *id)
108 {
109   bNodeTree *ntree = node_tree_from_ID(id);
110   if (id == NULL || ntree == NULL) {
111     return;
112   }
113 
114   /* TODO(sergey): With the new dependency graph it
115    * should be just enough to only tag ntree itself,
116    * all the users of this tree will have update
117    * flushed from the tree,
118    */
119   DEG_id_tag_update(&ntree->id, 0);
120 
121   if (ntree->type == NTREE_SHADER) {
122     DEG_id_tag_update(id, 0);
123 
124     if (GS(id->name) == ID_MA) {
125       WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
126     }
127     else if (GS(id->name) == ID_LA) {
128       WM_main_add_notifier(NC_LAMP | ND_LIGHTING, id);
129     }
130     else if (GS(id->name) == ID_WO) {
131       WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
132     }
133   }
134   else if (ntree->type == NTREE_COMPOSIT) {
135     WM_main_add_notifier(NC_SCENE | ND_NODES, id);
136   }
137   else if (ntree->type == NTREE_TEXTURE) {
138     DEG_id_tag_update(id, 0);
139     WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
140   }
141   else if (id == &ntree->id) {
142     /* node groups */
143     DEG_id_tag_update(id, 0);
144   }
145 }
146 
ED_node_tag_update_nodetree(Main * bmain,bNodeTree * ntree,bNode * node)147 void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node)
148 {
149   if (!ntree) {
150     return;
151   }
152 
153   bool do_tag_update = true;
154   if (node != NULL) {
155     if (!node_connected_to_output(bmain, ntree, node)) {
156       do_tag_update = false;
157     }
158   }
159 
160   /* look through all datablocks, to support groups */
161   if (do_tag_update) {
162     FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
163       /* check if nodetree uses the group */
164       if (ntreeHasTree(tntree, ntree)) {
165         ED_node_tag_update_id(id);
166       }
167     }
168     FOREACH_NODETREE_END;
169   }
170 
171   if (ntree->type == NTREE_TEXTURE) {
172     ntreeTexCheckCyclics(ntree);
173   }
174 }
175 
compare_nodes(const bNode * a,const bNode * b)176 static bool compare_nodes(const bNode *a, const bNode *b)
177 {
178   /* These tell if either the node or any of the parent nodes is selected.
179    * A selected parent means an unselected node is also in foreground!
180    */
181   bool a_select = (a->flag & NODE_SELECT) != 0, b_select = (b->flag & NODE_SELECT) != 0;
182   bool a_active = (a->flag & NODE_ACTIVE) != 0, b_active = (b->flag & NODE_ACTIVE) != 0;
183 
184   /* if one is an ancestor of the other */
185   /* XXX there might be a better sorting algorithm for stable topological sort,
186    * this is O(n^2) worst case */
187   for (bNode *parent = a->parent; parent; parent = parent->parent) {
188     /* if b is an ancestor, it is always behind a */
189     if (parent == b) {
190       return true;
191     }
192     /* any selected ancestor moves the node forward */
193     if (parent->flag & NODE_ACTIVE) {
194       a_active = 1;
195     }
196     if (parent->flag & NODE_SELECT) {
197       a_select = 1;
198     }
199   }
200   for (bNode *parent = b->parent; parent; parent = parent->parent) {
201     /* if a is an ancestor, it is always behind b */
202     if (parent == a) {
203       return false;
204     }
205     /* any selected ancestor moves the node forward */
206     if (parent->flag & NODE_ACTIVE) {
207       b_active = 1;
208     }
209     if (parent->flag & NODE_SELECT) {
210       b_select = 1;
211     }
212   }
213 
214   /* if one of the nodes is in the background and the other not */
215   if ((a->flag & NODE_BACKGROUND) && !(b->flag & NODE_BACKGROUND)) {
216     return false;
217   }
218   if (!(a->flag & NODE_BACKGROUND) && (b->flag & NODE_BACKGROUND)) {
219     return true;
220   }
221 
222   /* if one has a higher selection state (active > selected > nothing) */
223   if (!b_active && a_active) {
224     return true;
225   }
226   if (!b_select && (a_active || a_select)) {
227     return true;
228   }
229 
230   return false;
231 }
232 
233 /* Sorts nodes by selection: unselected nodes first, then selected,
234  * then the active node at the very end. Relative order is kept intact!
235  */
ED_node_sort(bNodeTree * ntree)236 void ED_node_sort(bNodeTree *ntree)
237 {
238   /* merge sort is the algorithm of choice here */
239   int totnodes = BLI_listbase_count(&ntree->nodes);
240 
241   int k = 1;
242   while (k < totnodes) {
243     bNode *first_a = ntree->nodes.first;
244     bNode *first_b = first_a;
245 
246     do {
247       /* setup first_b pointer */
248       for (int b = 0; b < k && first_b; b++) {
249         first_b = first_b->next;
250       }
251       /* all batches merged? */
252       if (first_b == NULL) {
253         break;
254       }
255 
256       /* merge batches */
257       bNode *node_a = first_a;
258       bNode *node_b = first_b;
259       int a = 0;
260       int b = 0;
261       while (a < k && b < k && node_b) {
262         if (compare_nodes(node_a, node_b) == 0) {
263           node_a = node_a->next;
264           a++;
265         }
266         else {
267           bNode *tmp = node_b;
268           node_b = node_b->next;
269           b++;
270           BLI_remlink(&ntree->nodes, tmp);
271           BLI_insertlinkbefore(&ntree->nodes, node_a, tmp);
272         }
273       }
274 
275       /* setup first pointers for next batch */
276       first_b = node_b;
277       for (; b < k; b++) {
278         /* all nodes sorted? */
279         if (first_b == NULL) {
280           break;
281         }
282         first_b = first_b->next;
283       }
284       first_a = first_b;
285     } while (first_b);
286 
287     k = k << 1;
288   }
289 }
290 
do_node_internal_buttons(bContext * C,void * UNUSED (node_v),int event)291 static void do_node_internal_buttons(bContext *C, void *UNUSED(node_v), int event)
292 {
293   if (event == B_NODE_EXEC) {
294     SpaceNode *snode = CTX_wm_space_node(C);
295     if (snode && snode->id) {
296       ED_node_tag_update_id(snode->id);
297     }
298   }
299 }
300 
node_uiblocks_init(const bContext * C,bNodeTree * ntree)301 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
302 {
303 
304   /* add node uiBlocks in drawing order - prevents events going to overlapping nodes */
305 
306   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
307     /* ui block */
308     char uiblockstr[32];
309     BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node);
310     node->block = UI_block_begin(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
311     UI_block_func_handle_set(node->block, do_node_internal_buttons, node);
312 
313     /* this cancels events for background nodes */
314     UI_block_flag_enable(node->block, UI_BLOCK_CLIP_EVENTS);
315   }
316 }
317 
node_to_view(struct bNode * node,float x,float y,float * rx,float * ry)318 void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry)
319 {
320   nodeToView(node, x, y, rx, ry);
321   *rx *= UI_DPI_FAC;
322   *ry *= UI_DPI_FAC;
323 }
324 
node_to_updated_rect(struct bNode * node,rctf * r_rect)325 void node_to_updated_rect(struct bNode *node, rctf *r_rect)
326 {
327   node_to_view(node, node->offsetx, node->offsety, &r_rect->xmin, &r_rect->ymax);
328   node_to_view(node,
329                node->offsetx + node->width,
330                node->offsety - node->height,
331                &r_rect->xmax,
332                &r_rect->ymin);
333 }
334 
node_from_view(struct bNode * node,float x,float y,float * rx,float * ry)335 void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry)
336 {
337   x /= UI_DPI_FAC;
338   y /= UI_DPI_FAC;
339   nodeFromView(node, x, y, rx, ry);
340 }
341 
342 /* based on settings in node, sets drawing rect info. each redraw! */
node_update_basis(const bContext * C,bNodeTree * ntree,bNode * node)343 static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
344 {
345   uiLayout *layout, *row;
346 
347   PointerRNA nodeptr;
348   RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
349 
350   /* get "global" coords */
351   float locx, locy;
352   node_to_view(node, 0.0f, 0.0f, &locx, &locy);
353   float dy = locy;
354 
355   /* header */
356   dy -= NODE_DY;
357 
358   /* little bit space in top */
359   if (node->outputs.first) {
360     dy -= NODE_DYS / 2;
361   }
362 
363   /* output sockets */
364   bool add_output_space = false;
365 
366   int buty;
367   LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
368     if (nodeSocketIsHidden(nsock)) {
369       continue;
370     }
371 
372     PointerRNA sockptr;
373     RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
374 
375     layout = UI_block_layout(node->block,
376                              UI_LAYOUT_VERTICAL,
377                              UI_LAYOUT_PANEL,
378                              locx + NODE_DYS,
379                              dy,
380                              NODE_WIDTH(node) - NODE_DY,
381                              NODE_DY,
382                              0,
383                              UI_style_get_dpi());
384 
385     if (node->flag & NODE_MUTED) {
386       uiLayoutSetActive(layout, false);
387     }
388 
389     /* context pointers for current node and socket */
390     uiLayoutSetContextPointer(layout, "node", &nodeptr);
391     uiLayoutSetContextPointer(layout, "socket", &sockptr);
392 
393     /* align output buttons to the right */
394     row = uiLayoutRow(layout, 1);
395     uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
396     const char *socket_label = nodeSocketLabel(nsock);
397     nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label));
398 
399     UI_block_align_end(node->block);
400     UI_block_layout_resolve(node->block, NULL, &buty);
401 
402     /* ensure minimum socket height in case layout is empty */
403     buty = min_ii(buty, dy - NODE_DY);
404 
405     nsock->locx = locx + NODE_WIDTH(node);
406     /* place the socket circle in the middle of the layout */
407     nsock->locy = 0.5f * (dy + buty);
408 
409     dy = buty;
410     if (nsock->next) {
411       dy -= NODE_SOCKDY;
412     }
413 
414     add_output_space = true;
415   }
416 
417   if (add_output_space) {
418     dy -= NODE_DY / 4;
419   }
420 
421   node->prvr.xmin = locx + NODE_DYS;
422   node->prvr.xmax = locx + NODE_WIDTH(node) - NODE_DYS;
423 
424   /* preview rect? */
425   if (node->flag & NODE_PREVIEW) {
426     float aspect = 1.0f;
427 
428     if (node->preview_xsize && node->preview_ysize) {
429       aspect = (float)node->preview_ysize / (float)node->preview_xsize;
430     }
431 
432     dy -= NODE_DYS / 2;
433     node->prvr.ymax = dy;
434 
435     if (aspect <= 1.0f) {
436       node->prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
437     }
438     else {
439       /* width correction of image */
440       /* XXX huh? (ton) */
441       float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect;
442 
443       node->prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
444 
445       node->prvr.xmin += 0.5f * dx;
446       node->prvr.xmax -= 0.5f * dx;
447     }
448 
449     dy = node->prvr.ymin - NODE_DYS / 2;
450 
451     /* make sure that maximums are bigger or equal to minimums */
452     if (node->prvr.xmax < node->prvr.xmin) {
453       SWAP(float, node->prvr.xmax, node->prvr.xmin);
454     }
455     if (node->prvr.ymax < node->prvr.ymin) {
456       SWAP(float, node->prvr.ymax, node->prvr.ymin);
457     }
458   }
459 
460   /* buttons rect? */
461   if (node->typeinfo->draw_buttons && (node->flag & NODE_OPTIONS)) {
462     dy -= NODE_DYS / 2;
463 
464     /* set this for uifunc() that don't use layout engine yet */
465     node->butr.xmin = 0;
466     node->butr.xmax = NODE_WIDTH(node) - 2 * NODE_DYS;
467     node->butr.ymin = 0;
468     node->butr.ymax = 0;
469 
470     layout = UI_block_layout(node->block,
471                              UI_LAYOUT_VERTICAL,
472                              UI_LAYOUT_PANEL,
473                              locx + NODE_DYS,
474                              dy,
475                              node->butr.xmax,
476                              0,
477                              0,
478                              UI_style_get_dpi());
479 
480     if (node->flag & NODE_MUTED) {
481       uiLayoutSetActive(layout, false);
482     }
483 
484     uiLayoutSetContextPointer(layout, "node", &nodeptr);
485 
486     node->typeinfo->draw_buttons(layout, (bContext *)C, &nodeptr);
487 
488     UI_block_align_end(node->block);
489     UI_block_layout_resolve(node->block, NULL, &buty);
490 
491     dy = buty - NODE_DYS / 2;
492   }
493 
494   /* input sockets */
495   LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
496     if (nodeSocketIsHidden(nsock)) {
497       continue;
498     }
499 
500     PointerRNA sockptr;
501     RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
502 
503     layout = UI_block_layout(node->block,
504                              UI_LAYOUT_VERTICAL,
505                              UI_LAYOUT_PANEL,
506                              locx + NODE_DYS,
507                              dy,
508                              NODE_WIDTH(node) - NODE_DY,
509                              NODE_DY,
510                              0,
511                              UI_style_get_dpi());
512 
513     if (node->flag & NODE_MUTED) {
514       uiLayoutSetActive(layout, false);
515     }
516 
517     /* context pointers for current node and socket */
518     uiLayoutSetContextPointer(layout, "node", &nodeptr);
519     uiLayoutSetContextPointer(layout, "socket", &sockptr);
520 
521     row = uiLayoutRow(layout, 1);
522 
523     const char *socket_label = nodeSocketLabel(nsock);
524     nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label));
525 
526     UI_block_align_end(node->block);
527     UI_block_layout_resolve(node->block, NULL, &buty);
528 
529     /* ensure minimum socket height in case layout is empty */
530     buty = min_ii(buty, dy - NODE_DY);
531 
532     nsock->locx = locx;
533     /* place the socket circle in the middle of the layout */
534     nsock->locy = 0.5f * (dy + buty);
535 
536     dy = buty;
537     if (nsock->next) {
538       dy -= NODE_SOCKDY;
539     }
540   }
541 
542   /* little bit space in end */
543   if (node->inputs.first || (node->flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0) {
544     dy -= NODE_DYS / 2;
545   }
546 
547   node->totr.xmin = locx;
548   node->totr.xmax = locx + NODE_WIDTH(node);
549   node->totr.ymax = locy;
550   node->totr.ymin = min_ff(dy, locy - 2 * NODE_DY);
551 
552   /* Set the block bounds to clip mouse events from underlying nodes.
553    * Add a margin for sockets on each side.
554    */
555   UI_block_bounds_set_explicit(node->block,
556                                node->totr.xmin - NODE_SOCKSIZE,
557                                node->totr.ymin,
558                                node->totr.xmax + NODE_SOCKSIZE,
559                                node->totr.ymax);
560 }
561 
562 /* based on settings in node, sets drawing rect info. each redraw! */
node_update_hidden(bNode * node)563 static void node_update_hidden(bNode *node)
564 {
565   int totin = 0, totout = 0;
566 
567   /* get "global" coords */
568   float locx, locy;
569   node_to_view(node, 0.0f, 0.0f, &locx, &locy);
570 
571   /* calculate minimal radius */
572   LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
573     if (!nodeSocketIsHidden(nsock)) {
574       totin++;
575     }
576   }
577   LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
578     if (!nodeSocketIsHidden(nsock)) {
579       totout++;
580     }
581   }
582 
583   float hiddenrad = HIDDEN_RAD;
584   float tot = MAX2(totin, totout);
585   if (tot > 4) {
586     hiddenrad += 5.0f * (float)(tot - 4);
587   }
588 
589   node->totr.xmin = locx;
590   node->totr.xmax = locx + max_ff(NODE_WIDTH(node), 2 * hiddenrad);
591   node->totr.ymax = locy + (hiddenrad - 0.5f * NODE_DY);
592   node->totr.ymin = node->totr.ymax - 2 * hiddenrad;
593 
594   /* output sockets */
595   float rad = (float)M_PI / (1.0f + (float)totout);
596   float drad = rad;
597 
598   LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
599     if (!nodeSocketIsHidden(nsock)) {
600       nsock->locx = node->totr.xmax - hiddenrad + sinf(rad) * hiddenrad;
601       nsock->locy = node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad;
602       rad += drad;
603     }
604   }
605 
606   /* input sockets */
607   rad = drad = -(float)M_PI / (1.0f + (float)totin);
608 
609   LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
610     if (!nodeSocketIsHidden(nsock)) {
611       nsock->locx = node->totr.xmin + hiddenrad + sinf(rad) * hiddenrad;
612       nsock->locy = node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad;
613       rad += drad;
614     }
615   }
616 
617   /* Set the block bounds to clip mouse events from underlying nodes.
618    * Add a margin for sockets on each side.
619    */
620   UI_block_bounds_set_explicit(node->block,
621                                node->totr.xmin - NODE_SOCKSIZE,
622                                node->totr.ymin,
623                                node->totr.xmax + NODE_SOCKSIZE,
624                                node->totr.ymax);
625 }
626 
node_update_default(const bContext * C,bNodeTree * ntree,bNode * node)627 void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
628 {
629   if (node->flag & NODE_HIDDEN) {
630     node_update_hidden(node);
631   }
632   else {
633     node_update_basis(C, ntree, node);
634   }
635 }
636 
node_select_area_default(bNode * node,int x,int y)637 int node_select_area_default(bNode *node, int x, int y)
638 {
639   return BLI_rctf_isect_pt(&node->totr, x, y);
640 }
641 
node_tweak_area_default(bNode * node,int x,int y)642 int node_tweak_area_default(bNode *node, int x, int y)
643 {
644   return BLI_rctf_isect_pt(&node->totr, x, y);
645 }
646 
node_get_colorid(bNode * node)647 int node_get_colorid(bNode *node)
648 {
649   switch (node->typeinfo->nclass) {
650     case NODE_CLASS_INPUT:
651       return TH_NODE_INPUT;
652     case NODE_CLASS_OUTPUT:
653       return (node->flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE;
654     case NODE_CLASS_CONVERTOR:
655       return TH_NODE_CONVERTOR;
656     case NODE_CLASS_OP_COLOR:
657       return TH_NODE_COLOR;
658     case NODE_CLASS_OP_VECTOR:
659       return TH_NODE_VECTOR;
660     case NODE_CLASS_OP_FILTER:
661       return TH_NODE_FILTER;
662     case NODE_CLASS_GROUP:
663       return TH_NODE_GROUP;
664     case NODE_CLASS_INTERFACE:
665       return TH_NODE_INTERFACE;
666     case NODE_CLASS_MATTE:
667       return TH_NODE_MATTE;
668     case NODE_CLASS_DISTORT:
669       return TH_NODE_DISTORT;
670     case NODE_CLASS_TEXTURE:
671       return TH_NODE_TEXTURE;
672     case NODE_CLASS_SHADER:
673       return TH_NODE_SHADER;
674     case NODE_CLASS_SCRIPT:
675       return TH_NODE_SCRIPT;
676     case NODE_CLASS_PATTERN:
677       return TH_NODE_PATTERN;
678     case NODE_CLASS_LAYOUT:
679       return TH_NODE_LAYOUT;
680     default:
681       return TH_NODE;
682   }
683 }
684 
685 /* note: in cmp_util.c is similar code, for node_compo_pass_on()
686  *       the same goes for shader and texture nodes. */
687 /* note: in node_edit.c is similar code, for untangle node */
node_draw_mute_line(View2D * v2d,SpaceNode * snode,bNode * node)688 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
689 {
690   GPU_blend(GPU_BLEND_ALPHA);
691 
692   LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
693     node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1);
694   }
695 
696   GPU_blend(GPU_BLEND_NONE);
697 }
698 
699 /* flags used in gpu_shader_keyframe_diamond_frag.glsl */
700 #define MARKER_SHAPE_DIAMOND 0x1
701 #define MARKER_SHAPE_SQUARE 0xC
702 #define MARKER_SHAPE_CIRCLE 0x2
703 #define MARKER_SHAPE_INNER_DOT 0x10
704 
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)705 static void node_socket_draw(const bNodeSocket *sock,
706                              const float color[4],
707                              const float color_outline[4],
708                              float size,
709                              int locx,
710                              int locy,
711                              uint pos_id,
712                              uint col_id,
713                              uint shape_id,
714                              uint size_id,
715                              uint outline_col_id)
716 {
717   int flags;
718 
719   /* sets shape flags */
720   switch (sock->display_shape) {
721     case SOCK_DISPLAY_SHAPE_DIAMOND:
722     case SOCK_DISPLAY_SHAPE_DIAMOND_DOT:
723       flags = MARKER_SHAPE_DIAMOND;
724       break;
725     case SOCK_DISPLAY_SHAPE_SQUARE:
726     case SOCK_DISPLAY_SHAPE_SQUARE_DOT:
727       flags = MARKER_SHAPE_SQUARE;
728       break;
729     default:
730     case SOCK_DISPLAY_SHAPE_CIRCLE:
731     case SOCK_DISPLAY_SHAPE_CIRCLE_DOT:
732       flags = MARKER_SHAPE_CIRCLE;
733       break;
734   }
735 
736   if (ELEM(sock->display_shape,
737            SOCK_DISPLAY_SHAPE_DIAMOND_DOT,
738            SOCK_DISPLAY_SHAPE_SQUARE_DOT,
739            SOCK_DISPLAY_SHAPE_CIRCLE_DOT)) {
740     flags |= MARKER_SHAPE_INNER_DOT;
741   }
742 
743   immAttr4fv(col_id, color);
744   immAttr1u(shape_id, flags);
745   immAttr1f(size_id, size);
746   immAttr4fv(outline_col_id, color_outline);
747   immVertex2f(pos_id, locx, locy);
748 }
749 
node_socket_outline_color_get(bool selected,float r_outline_color[4])750 static void node_socket_outline_color_get(bool selected, float r_outline_color[4])
751 {
752   if (selected) {
753     UI_GetThemeColor4fv(TH_TEXT_HI, r_outline_color);
754     r_outline_color[3] = 0.9f;
755   }
756   else {
757     copy_v4_fl(r_outline_color, 0.0f);
758     r_outline_color[3] = 0.6f;
759   }
760 }
761 
762 /* Usual convention here would be node_socket_get_color(), but that's already used (for setting a
763  * color property socket). */
node_socket_color_get(bContext * C,bNodeTree * ntree,PointerRNA * node_ptr,bNodeSocket * sock,float r_color[4])764 void node_socket_color_get(
765     bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4])
766 {
767   PointerRNA ptr;
768 
769   BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node));
770   RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
771 
772   sock->typeinfo->draw_color(C, &ptr, node_ptr, r_color);
773 
774   bNode *node = node_ptr->data;
775   if (node->flag & NODE_MUTED) {
776     r_color[3] *= 0.25f;
777   }
778 }
779 
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)780 static void node_socket_draw_nested(const bContext *C,
781                                     bNodeTree *ntree,
782                                     PointerRNA *node_ptr,
783                                     bNodeSocket *sock,
784                                     uint pos_id,
785                                     uint col_id,
786                                     uint shape_id,
787                                     uint size_id,
788                                     uint outline_col_id,
789                                     float size,
790                                     bool selected)
791 {
792   float color[4];
793   float outline_color[4];
794 
795   node_socket_color_get((bContext *)C, ntree, node_ptr, sock, color);
796   node_socket_outline_color_get(selected, outline_color);
797 
798   node_socket_draw(sock,
799                    color,
800                    outline_color,
801                    size,
802                    sock->locx,
803                    sock->locy,
804                    pos_id,
805                    col_id,
806                    shape_id,
807                    size_id,
808                    outline_col_id);
809 }
810 
811 /**
812  * Draw a single node socket at default size.
813  * \note this is only called from external code, internally #node_socket_draw_nested() is used for
814  *       optimized drawing of multiple/all sockets of a node.
815  */
ED_node_socket_draw(bNodeSocket * sock,const rcti * rect,const float color[4],float scale)816 void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
817 {
818   const float size = 2.25f * NODE_SOCKSIZE * scale;
819   rcti draw_rect = *rect;
820   float outline_color[4] = {0};
821 
822   node_socket_outline_color_get(sock->flag & SELECT, outline_color);
823 
824   BLI_rcti_resize(&draw_rect, size, size);
825 
826   GPUVertFormat *format = immVertexFormat();
827   uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
828   uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
829   uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
830   uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
831   uint outline_col_id = GPU_vertformat_attr_add(
832       format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
833 
834   eGPUBlend state = GPU_blend_get();
835   GPU_blend(GPU_BLEND_ALPHA);
836   GPU_program_point_size(true);
837 
838   immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
839   immUniform1f("outline_scale", 0.7f);
840   immUniform2f("ViewportSize", -1.0f, -1.0f);
841 
842   /* Single point */
843   immBegin(GPU_PRIM_POINTS, 1);
844   node_socket_draw(sock,
845                    color,
846                    outline_color,
847                    BLI_rcti_size_y(&draw_rect),
848                    BLI_rcti_cent_x(&draw_rect),
849                    BLI_rcti_cent_y(&draw_rect),
850                    pos_id,
851                    col_id,
852                    shape_id,
853                    size_id,
854                    outline_col_id);
855   immEnd();
856 
857   immUnbindProgram();
858   GPU_program_point_size(false);
859 
860   /* Restore. */
861   GPU_blend(state);
862 }
863 
864 /* **************  Socket callbacks *********** */
865 
node_draw_preview_background(rctf * rect)866 static void node_draw_preview_background(rctf *rect)
867 {
868   GPUVertFormat *format = immVertexFormat();
869   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
870 
871   immBindBuiltinProgram(GPU_SHADER_2D_CHECKER);
872 
873   /* Drawing the checkerboard. */
874   const float checker_dark = UI_ALPHA_CHECKER_DARK / 255.0f;
875   const float checker_light = UI_ALPHA_CHECKER_LIGHT / 255.0f;
876   immUniform4f("color1", checker_dark, checker_dark, checker_dark, 1.0f);
877   immUniform4f("color2", checker_light, checker_light, checker_light, 1.0f);
878   immUniform1i("size", 8);
879   immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
880   immUnbindProgram();
881 }
882 
883 /* not a callback */
node_draw_preview(bNodePreview * preview,rctf * prv)884 static void node_draw_preview(bNodePreview *preview, rctf *prv)
885 {
886   float xrect = BLI_rctf_size_x(prv);
887   float yrect = BLI_rctf_size_y(prv);
888   float xscale = xrect / ((float)preview->xsize);
889   float yscale = yrect / ((float)preview->ysize);
890   float scale;
891 
892   /* uniform scale and offset */
893   rctf draw_rect = *prv;
894   if (xscale < yscale) {
895     float offset = 0.5f * (yrect - ((float)preview->ysize) * xscale);
896     draw_rect.ymin += offset;
897     draw_rect.ymax -= offset;
898     scale = xscale;
899   }
900   else {
901     float offset = 0.5f * (xrect - ((float)preview->xsize) * yscale);
902     draw_rect.xmin += offset;
903     draw_rect.xmax -= offset;
904     scale = yscale;
905   }
906 
907   node_draw_preview_background(&draw_rect);
908 
909   GPU_blend(GPU_BLEND_ALPHA);
910   /* premul graphics */
911   GPU_blend(GPU_BLEND_ALPHA);
912 
913   IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
914   immDrawPixelsTex(&state,
915                    draw_rect.xmin,
916                    draw_rect.ymin,
917                    preview->xsize,
918                    preview->ysize,
919                    GPU_RGBA8,
920                    true,
921                    preview->rect,
922                    scale,
923                    scale,
924                    NULL);
925 
926   GPU_blend(GPU_BLEND_NONE);
927 
928   uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
929   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
930   immUniformThemeColorShadeAlpha(TH_BACK, -15, +100);
931   imm_draw_box_wire_2d(pos, draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
932   immUnbindProgram();
933 }
934 
935 /* common handle function for operator buttons that need to select the node first */
node_toggle_button_cb(struct bContext * C,void * node_argv,void * op_argv)936 static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv)
937 {
938   bNode *node = (bNode *)node_argv;
939   const char *opname = (const char *)op_argv;
940 
941   /* select & activate only the button's node */
942   node_select_single(C, node);
943 
944   WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, NULL);
945 }
946 
node_draw_shadow(SpaceNode * snode,bNode * node,float radius,float alpha)947 void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha)
948 {
949   rctf *rct = &node->totr;
950   UI_draw_roundbox_corner_set(UI_CNR_ALL);
951   ui_draw_dropshadow(rct, radius, snode->aspect, alpha, node->flag & SELECT);
952 }
953 
node_draw_sockets(View2D * v2d,const bContext * C,bNodeTree * ntree,bNode * node,bool draw_outputs,bool select_all)954 void node_draw_sockets(View2D *v2d,
955                        const bContext *C,
956                        bNodeTree *ntree,
957                        bNode *node,
958                        bool draw_outputs,
959                        bool select_all)
960 {
961   const uint total_input_len = BLI_listbase_count(&node->inputs);
962   const uint total_output_len = BLI_listbase_count(&node->outputs);
963 
964   if (total_input_len + total_output_len == 0) {
965     return;
966   }
967 
968   PointerRNA node_ptr;
969   RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
970 
971   bool selected = false;
972 
973   GPUVertFormat *format = immVertexFormat();
974   uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
975   uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
976   uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
977   uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
978   uint outline_col_id = GPU_vertformat_attr_add(
979       format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
980 
981   GPU_blend(GPU_BLEND_ALPHA);
982   GPU_program_point_size(true);
983   immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
984   immUniform1f("outline_scale", 0.7f);
985   immUniform2f("ViewportSize", -1.0f, -1.0f);
986 
987   /* set handle size */
988   float scale;
989   UI_view2d_scale_get(v2d, &scale, NULL);
990   scale *= 2.25f * NODE_SOCKSIZE;
991 
992   if (!select_all) {
993     immBeginAtMost(GPU_PRIM_POINTS, total_input_len + total_output_len);
994   }
995 
996   /* socket inputs */
997   short selected_input_len = 0;
998   bNodeSocket *sock;
999   for (sock = node->inputs.first; sock; sock = sock->next) {
1000     if (nodeSocketIsHidden(sock)) {
1001       continue;
1002     }
1003     if (select_all || (sock->flag & SELECT)) {
1004       selected_input_len++;
1005       continue;
1006     }
1007 
1008     node_socket_draw_nested(C,
1009                             ntree,
1010                             &node_ptr,
1011                             sock,
1012                             pos_id,
1013                             col_id,
1014                             shape_id,
1015                             size_id,
1016                             outline_col_id,
1017                             scale,
1018                             selected);
1019   }
1020 
1021   /* socket outputs */
1022   short selected_output_len = 0;
1023   if (draw_outputs) {
1024     for (sock = node->outputs.first; sock; sock = sock->next) {
1025       if (nodeSocketIsHidden(sock)) {
1026         continue;
1027       }
1028       if (select_all || (sock->flag & SELECT)) {
1029         selected_output_len++;
1030         continue;
1031       }
1032 
1033       node_socket_draw_nested(C,
1034                               ntree,
1035                               &node_ptr,
1036                               sock,
1037                               pos_id,
1038                               col_id,
1039                               shape_id,
1040                               size_id,
1041                               outline_col_id,
1042                               scale,
1043                               selected);
1044     }
1045   }
1046 
1047   if (!select_all) {
1048     immEnd();
1049   }
1050 
1051   /* go back and draw selected sockets */
1052   if (selected_input_len + selected_output_len > 0) {
1053     /* outline for selected sockets */
1054 
1055     selected = true;
1056 
1057     immBegin(GPU_PRIM_POINTS, selected_input_len + selected_output_len);
1058 
1059     if (selected_input_len) {
1060       /* socket inputs */
1061       for (sock = node->inputs.first; sock; sock = sock->next) {
1062         if (nodeSocketIsHidden(sock)) {
1063           continue;
1064         }
1065         if (select_all || (sock->flag & SELECT)) {
1066           node_socket_draw_nested(C,
1067                                   ntree,
1068                                   &node_ptr,
1069                                   sock,
1070                                   pos_id,
1071                                   col_id,
1072                                   shape_id,
1073                                   size_id,
1074                                   outline_col_id,
1075                                   scale,
1076                                   selected);
1077           if (--selected_input_len == 0) {
1078             break; /* stop as soon as last one is drawn */
1079           }
1080         }
1081       }
1082     }
1083 
1084     if (selected_output_len) {
1085       /* socket outputs */
1086       for (sock = node->outputs.first; sock; sock = sock->next) {
1087         if (nodeSocketIsHidden(sock)) {
1088           continue;
1089         }
1090         if (select_all || (sock->flag & SELECT)) {
1091           node_socket_draw_nested(C,
1092                                   ntree,
1093                                   &node_ptr,
1094                                   sock,
1095                                   pos_id,
1096                                   col_id,
1097                                   shape_id,
1098                                   size_id,
1099                                   outline_col_id,
1100                                   scale,
1101                                   selected);
1102           if (--selected_output_len == 0) {
1103             break; /* stop as soon as last one is drawn */
1104           }
1105         }
1106       }
1107     }
1108 
1109     immEnd();
1110   }
1111 
1112   immUnbindProgram();
1113 
1114   GPU_program_point_size(false);
1115   GPU_blend(GPU_BLEND_NONE);
1116 }
1117 
node_draw_basis(const bContext * C,ARegion * region,SpaceNode * snode,bNodeTree * ntree,bNode * node,bNodeInstanceKey key)1118 static void node_draw_basis(const bContext *C,
1119                             ARegion *region,
1120                             SpaceNode *snode,
1121                             bNodeTree *ntree,
1122                             bNode *node,
1123                             bNodeInstanceKey key)
1124 {
1125   /* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
1126   float iconbutw = 0.8f * UI_UNIT_X;
1127 
1128   View2D *v2d = &region->v2d;
1129 
1130   /* skip if out of view */
1131   if (BLI_rctf_isect(&node->totr, &v2d->cur, NULL) == false) {
1132     UI_block_end(C, node->block);
1133     node->block = NULL;
1134     return;
1135   }
1136 
1137   /* shadow */
1138   node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
1139 
1140   float color[4];
1141   int color_id = node_get_colorid(node);
1142   if (node->flag & NODE_MUTED) {
1143     /* Muted nodes are semi-transparent and colorless. */
1144     UI_GetThemeColor3fv(TH_NODE, color);
1145     color[3] = 0.25f;
1146   }
1147   else {
1148     /* Opaque headers for regular nodes. */
1149     UI_GetThemeColor3fv(color_id, color);
1150     color[3] = 1.0f;
1151   }
1152 
1153   GPU_line_width(1.0f);
1154 
1155   rctf *rct = &node->totr;
1156   UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
1157   UI_draw_roundbox_aa(
1158       true, rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD, color);
1159 
1160   /* show/hide icons */
1161   float iconofs = rct->xmax - 0.35f * U.widget_unit;
1162 
1163   /* preview */
1164   if (node->typeinfo->flag & NODE_PREVIEW) {
1165     uiBut *but;
1166     iconofs -= iconbutw;
1167     UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
1168     but = uiDefIconBut(node->block,
1169                        UI_BTYPE_BUT_TOGGLE,
1170                        B_REDR,
1171                        ICON_MATERIAL,
1172                        iconofs,
1173                        rct->ymax - NODE_DY,
1174                        iconbutw,
1175                        UI_UNIT_Y,
1176                        NULL,
1177                        0,
1178                        0,
1179                        0,
1180                        0,
1181                        "");
1182     UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_preview_toggle");
1183     /* XXX this does not work when node is activated and the operator called right afterwards,
1184      * since active ID is not updated yet (needs to process the notifier).
1185      * This can only work as visual indicator!
1186      */
1187     //      if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
1188     //          UI_but_flag_enable(but, UI_BUT_DISABLED);
1189     UI_block_emboss_set(node->block, UI_EMBOSS);
1190   }
1191   /* group edit */
1192   if (node->type == NODE_GROUP) {
1193     uiBut *but;
1194     iconofs -= iconbutw;
1195     UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
1196     but = uiDefIconBut(node->block,
1197                        UI_BTYPE_BUT_TOGGLE,
1198                        B_REDR,
1199                        ICON_NODETREE,
1200                        iconofs,
1201                        rct->ymax - NODE_DY,
1202                        iconbutw,
1203                        UI_UNIT_Y,
1204                        NULL,
1205                        0,
1206                        0,
1207                        0,
1208                        0,
1209                        "");
1210     UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_group_edit");
1211     UI_block_emboss_set(node->block, UI_EMBOSS);
1212   }
1213   if (node->type == NODE_CUSTOM && node->typeinfo->ui_icon != ICON_NONE) {
1214     iconofs -= iconbutw;
1215     UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
1216     uiDefIconBut(node->block,
1217                  UI_BTYPE_BUT,
1218                  0,
1219                  node->typeinfo->ui_icon,
1220                  iconofs,
1221                  rct->ymax - NODE_DY,
1222                  iconbutw,
1223                  UI_UNIT_Y,
1224                  NULL,
1225                  0,
1226                  0,
1227                  0,
1228                  0,
1229                  "");
1230     UI_block_emboss_set(node->block, UI_EMBOSS);
1231   }
1232 
1233   /* title */
1234   if (node->flag & SELECT) {
1235     UI_GetThemeColor4fv(TH_SELECT, color);
1236   }
1237   else {
1238     UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
1239   }
1240 
1241   /* open/close entirely? */
1242   {
1243     uiBut *but;
1244     int but_size = U.widget_unit * 0.8f;
1245     /* XXX button uses a custom triangle draw below, so make it invisible without icon */
1246     UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
1247     but = uiDefBut(node->block,
1248                    UI_BTYPE_BUT_TOGGLE,
1249                    B_REDR,
1250                    "",
1251                    rct->xmin + 0.35f * U.widget_unit,
1252                    rct->ymax - NODE_DY / 2.2f - but_size / 2,
1253                    but_size,
1254                    but_size,
1255                    NULL,
1256                    0,
1257                    0,
1258                    0,
1259                    0,
1260                    "");
1261     UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
1262     UI_block_emboss_set(node->block, UI_EMBOSS);
1263 
1264     UI_GetThemeColor4fv(TH_TEXT, color);
1265     /* custom draw function for this button */
1266     UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, rct->ymax - NODE_DY / 2.2f, 'v', color);
1267   }
1268 
1269   char showname[128]; /* 128 used below */
1270   nodeLabel(ntree, node, showname, sizeof(showname));
1271 
1272   uiBut *but = uiDefBut(node->block,
1273                         UI_BTYPE_LABEL,
1274                         0,
1275                         showname,
1276                         (int)(rct->xmin + NODE_MARGIN_X),
1277                         (int)(rct->ymax - NODE_DY),
1278                         (short)(iconofs - rct->xmin - (18.0f * U.dpi_fac)),
1279                         (short)NODE_DY,
1280                         NULL,
1281                         0,
1282                         0,
1283                         0,
1284                         0,
1285                         "");
1286   if (node->flag & NODE_MUTED) {
1287     UI_but_flag_enable(but, UI_BUT_INACTIVE);
1288   }
1289 
1290   /* body */
1291   if (!nodeIsRegistered(node)) {
1292     /* use warning color to indicate undefined types */
1293     UI_GetThemeColor4fv(TH_REDALERT, color);
1294   }
1295   else if (node->flag & NODE_MUTED) {
1296     /* Muted nodes are semi-transparent and colorless. */
1297     UI_GetThemeColor4fv(TH_NODE, color);
1298   }
1299   else if (node->flag & NODE_CUSTOM_COLOR) {
1300     rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
1301   }
1302   else {
1303     UI_GetThemeColor4fv(TH_NODE, color);
1304   }
1305 
1306   if (node->flag & NODE_MUTED) {
1307     color[3] = 0.5f;
1308   }
1309 
1310   UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
1311   UI_draw_roundbox_aa(
1312       true, rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD, color);
1313 
1314   /* outline active and selected emphasis */
1315   if (node->flag & SELECT) {
1316     UI_GetThemeColorShadeAlpha4fv(
1317         (node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
1318 
1319     UI_draw_roundbox_corner_set(UI_CNR_ALL);
1320     UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
1321   }
1322 
1323   /* disable lines */
1324   if (node->flag & NODE_MUTED) {
1325     node_draw_mute_line(v2d, snode, node);
1326   }
1327 
1328   node_draw_sockets(v2d, C, ntree, node, true, false);
1329 
1330   /* preview */
1331   bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data;
1332   if (node->flag & NODE_PREVIEW && previews) {
1333     bNodePreview *preview = BKE_node_instance_hash_lookup(previews, key);
1334     if (preview && (preview->xsize && preview->ysize)) {
1335       if (preview->rect && !BLI_rctf_is_empty(&node->prvr)) {
1336         node_draw_preview(preview, &node->prvr);
1337       }
1338     }
1339   }
1340 
1341   UI_block_end(C, node->block);
1342   UI_block_draw(C, node->block);
1343   node->block = NULL;
1344 }
1345 
node_draw_hidden(const bContext * C,ARegion * region,SpaceNode * snode,bNodeTree * ntree,bNode * node,bNodeInstanceKey UNUSED (key))1346 static void node_draw_hidden(const bContext *C,
1347                              ARegion *region,
1348                              SpaceNode *snode,
1349                              bNodeTree *ntree,
1350                              bNode *node,
1351                              bNodeInstanceKey UNUSED(key))
1352 {
1353   rctf *rct = &node->totr;
1354   float centy = BLI_rctf_cent_y(rct);
1355   float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
1356 
1357   View2D *v2d = &region->v2d;
1358 
1359   float scale;
1360   UI_view2d_scale_get(v2d, &scale, NULL);
1361 
1362   /* shadow */
1363   node_draw_shadow(snode, node, hiddenrad, 1.0f);
1364 
1365   /* body */
1366   float color[4];
1367   int color_id = node_get_colorid(node);
1368   if (node->flag & NODE_MUTED) {
1369     /* Muted nodes are semi-transparent and colorless. */
1370     UI_GetThemeColor4fv(TH_NODE, color);
1371     color[3] = 0.25f;
1372   }
1373   else {
1374     UI_GetThemeColor4fv(color_id, color);
1375   }
1376 
1377   UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
1378 
1379   /* outline active and selected emphasis */
1380   if (node->flag & SELECT) {
1381     UI_GetThemeColorShadeAlpha4fv(
1382         (node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
1383 
1384     UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
1385   }
1386 
1387   /* custom color inline */
1388   if (node->flag & NODE_CUSTOM_COLOR) {
1389     GPU_blend(GPU_BLEND_ALPHA);
1390     GPU_line_smooth(true);
1391 
1392     UI_draw_roundbox_3fv_alpha(false,
1393                                rct->xmin + 1,
1394                                rct->ymin + 1,
1395                                rct->xmax - 1,
1396                                rct->ymax - 1,
1397                                hiddenrad,
1398                                node->color,
1399                                1.0f);
1400 
1401     GPU_line_smooth(false);
1402     GPU_blend(GPU_BLEND_NONE);
1403   }
1404 
1405   /* title */
1406   if (node->flag & SELECT) {
1407     UI_GetThemeColor4fv(TH_SELECT, color);
1408   }
1409   else {
1410     UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
1411   }
1412 
1413   /* open entirely icon */
1414   {
1415     uiBut *but;
1416     int but_size = U.widget_unit * 0.8f;
1417     /* XXX button uses a custom triangle draw below, so make it invisible without icon */
1418     UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
1419     but = uiDefBut(node->block,
1420                    UI_BTYPE_BUT_TOGGLE,
1421                    B_REDR,
1422                    "",
1423                    rct->xmin + 0.35f * U.widget_unit,
1424                    centy - but_size / 2,
1425                    but_size,
1426                    but_size,
1427                    NULL,
1428                    0,
1429                    0,
1430                    0,
1431                    0,
1432                    "");
1433     UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
1434     UI_block_emboss_set(node->block, UI_EMBOSS);
1435 
1436     UI_GetThemeColor4fv(TH_TEXT, color);
1437     /* custom draw function for this button */
1438     UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, centy, 'h', color);
1439   }
1440 
1441   /* disable lines */
1442   if (node->flag & NODE_MUTED) {
1443     node_draw_mute_line(&region->v2d, snode, node);
1444   }
1445 
1446   char showname[128]; /* 128 is used below */
1447   nodeLabel(ntree, node, showname, sizeof(showname));
1448 
1449   /* XXX - don't print into self! */
1450   // if (node->flag & NODE_MUTED)
1451   //  BLI_snprintf(showname, sizeof(showname), "[%s]", showname);
1452 
1453   uiBut *but = uiDefBut(node->block,
1454                         UI_BTYPE_LABEL,
1455                         0,
1456                         showname,
1457                         round_fl_to_int(rct->xmin + NODE_MARGIN_X),
1458                         round_fl_to_int(centy - NODE_DY * 0.5f),
1459                         (short)(BLI_rctf_size_x(rct) - ((18.0f + 12.0f) * U.dpi_fac)),
1460                         (short)NODE_DY,
1461                         NULL,
1462                         0,
1463                         0,
1464                         0,
1465                         0,
1466                         "");
1467   if (node->flag & NODE_MUTED) {
1468     UI_but_flag_enable(but, UI_BUT_INACTIVE);
1469   }
1470 
1471   /* scale widget thing */
1472   uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1473   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1474 
1475   immUniformThemeColorShade(color_id, -10);
1476   float dx = 10.0f;
1477 
1478   immBegin(GPU_PRIM_LINES, 4);
1479   immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
1480   immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
1481 
1482   immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f);
1483   immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
1484   immEnd();
1485 
1486   immUniformThemeColorShade(color_id, 30);
1487   dx -= snode->aspect;
1488 
1489   immBegin(GPU_PRIM_LINES, 4);
1490   immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
1491   immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
1492 
1493   immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f);
1494   immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
1495   immEnd();
1496 
1497   immUnbindProgram();
1498 
1499   node_draw_sockets(v2d, C, ntree, node, true, false);
1500 
1501   UI_block_end(C, node->block);
1502   UI_block_draw(C, node->block);
1503   node->block = NULL;
1504 }
1505 
node_get_resize_cursor(int directions)1506 int node_get_resize_cursor(int directions)
1507 {
1508   if (directions == 0) {
1509     return WM_CURSOR_DEFAULT;
1510   }
1511   if ((directions & ~(NODE_RESIZE_TOP | NODE_RESIZE_BOTTOM)) == 0) {
1512     return WM_CURSOR_Y_MOVE;
1513   }
1514   if ((directions & ~(NODE_RESIZE_RIGHT | NODE_RESIZE_LEFT)) == 0) {
1515     return WM_CURSOR_X_MOVE;
1516   }
1517   return WM_CURSOR_EDIT;
1518 }
1519 
node_set_cursor(wmWindow * win,SpaceNode * snode,float cursor[2])1520 void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2])
1521 {
1522   bNodeTree *ntree = snode->edittree;
1523   bNode *node;
1524   bNodeSocket *sock;
1525   int wmcursor = WM_CURSOR_DEFAULT;
1526 
1527   if (ntree) {
1528     if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) {
1529       /* pass */
1530     }
1531     else {
1532       /* check nodes front to back */
1533       for (node = ntree->nodes.last; node; node = node->prev) {
1534         if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) {
1535           break; /* first hit on node stops */
1536         }
1537       }
1538       if (node) {
1539         int dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]);
1540         wmcursor = node_get_resize_cursor(dir);
1541       }
1542     }
1543   }
1544 
1545   WM_cursor_set(win, wmcursor);
1546 }
1547 
node_draw_default(const bContext * C,ARegion * region,SpaceNode * snode,bNodeTree * ntree,bNode * node,bNodeInstanceKey key)1548 void node_draw_default(const bContext *C,
1549                        ARegion *region,
1550                        SpaceNode *snode,
1551                        bNodeTree *ntree,
1552                        bNode *node,
1553                        bNodeInstanceKey key)
1554 {
1555   if (node->flag & NODE_HIDDEN) {
1556     node_draw_hidden(C, region, snode, ntree, node, key);
1557   }
1558   else {
1559     node_draw_basis(C, region, snode, ntree, node, key);
1560   }
1561 }
1562 
node_update(const bContext * C,bNodeTree * ntree,bNode * node)1563 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
1564 {
1565   if (node->typeinfo->draw_nodetype_prepare) {
1566     node->typeinfo->draw_nodetype_prepare(C, ntree, node);
1567   }
1568 }
1569 
node_update_nodetree(const bContext * C,bNodeTree * ntree)1570 void node_update_nodetree(const bContext *C, bNodeTree *ntree)
1571 {
1572   /* make sure socket "used" tags are correct, for displaying value buttons */
1573   ntreeTagUsedSockets(ntree);
1574 
1575   /* update nodes front to back, so children sizes get updated before parents */
1576   LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
1577     node_update(C, ntree, node);
1578   }
1579 }
1580 
node_draw(const bContext * C,ARegion * region,SpaceNode * snode,bNodeTree * ntree,bNode * node,bNodeInstanceKey key)1581 static void node_draw(const bContext *C,
1582                       ARegion *region,
1583                       SpaceNode *snode,
1584                       bNodeTree *ntree,
1585                       bNode *node,
1586                       bNodeInstanceKey key)
1587 {
1588   if (node->typeinfo->draw_nodetype) {
1589     node->typeinfo->draw_nodetype(C, region, snode, ntree, node, key);
1590   }
1591 }
1592 
1593 #define USE_DRAW_TOT_UPDATE
1594 
node_draw_nodetree(const bContext * C,ARegion * region,SpaceNode * snode,bNodeTree * ntree,bNodeInstanceKey parent_key)1595 void node_draw_nodetree(const bContext *C,
1596                         ARegion *region,
1597                         SpaceNode *snode,
1598                         bNodeTree *ntree,
1599                         bNodeInstanceKey parent_key)
1600 {
1601   if (ntree == NULL) {
1602     return; /* groups... */
1603   }
1604 
1605 #ifdef USE_DRAW_TOT_UPDATE
1606   if (ntree->nodes.first) {
1607     BLI_rctf_init_minmax(&region->v2d.tot);
1608   }
1609 #endif
1610 
1611   /* draw background nodes, last nodes in front */
1612   int a;
1613   bNode *node;
1614   for (a = 0, node = ntree->nodes.first; node; node = node->next, a++) {
1615     bNodeInstanceKey key;
1616 
1617 #ifdef USE_DRAW_TOT_UPDATE
1618     /* unrelated to background nodes, update the v2d->tot,
1619      * can be anywhere before we draw the scroll bars */
1620     BLI_rctf_union(&region->v2d.tot, &node->totr);
1621 #endif
1622 
1623     if (!(node->flag & NODE_BACKGROUND)) {
1624       continue;
1625     }
1626 
1627     key = BKE_node_instance_key(parent_key, ntree, node);
1628     node->nr = a; /* index of node in list, used for exec event code */
1629     node_draw(C, region, snode, ntree, node, key);
1630   }
1631 
1632   /* node lines */
1633   GPU_blend(GPU_BLEND_ALPHA);
1634   nodelink_batch_start(snode);
1635   LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
1636     if (!nodeLinkIsHidden(link)) {
1637       node_draw_link(&region->v2d, snode, link);
1638     }
1639   }
1640   nodelink_batch_end(snode);
1641   GPU_blend(GPU_BLEND_NONE);
1642 
1643   /* draw foreground nodes, last nodes in front */
1644   for (a = 0, node = ntree->nodes.first; node; node = node->next, a++) {
1645     bNodeInstanceKey key;
1646     if (node->flag & NODE_BACKGROUND) {
1647       continue;
1648     }
1649 
1650     key = BKE_node_instance_key(parent_key, ntree, node);
1651     node->nr = a; /* index of node in list, used for exec event code */
1652     node_draw(C, region, snode, ntree, node, key);
1653   }
1654 }
1655 
1656 /* draw tree path info in lower left corner */
draw_tree_path(SpaceNode * snode)1657 static void draw_tree_path(SpaceNode *snode)
1658 {
1659   char info[256];
1660 
1661   ED_node_tree_path_get_fixedbuf(snode, info, sizeof(info));
1662 
1663   UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
1664   BLF_draw_default(1.5f * UI_UNIT_X, 1.5f * UI_UNIT_Y, 0.0f, info, sizeof(info));
1665 }
1666 
snode_setup_v2d(SpaceNode * snode,ARegion * region,const float center[2])1667 static void snode_setup_v2d(SpaceNode *snode, ARegion *region, const float center[2])
1668 {
1669   View2D *v2d = &region->v2d;
1670 
1671   /* shift view to node tree center */
1672   UI_view2d_center_set(v2d, center[0], center[1]);
1673   UI_view2d_view_ortho(v2d);
1674 
1675   /* aspect+font, set each time */
1676   snode->aspect = BLI_rctf_size_x(&v2d->cur) / (float)region->winx;
1677   // XXX snode->curfont = uiSetCurFont_ext(snode->aspect);
1678 }
1679 
draw_nodetree(const bContext * C,ARegion * region,bNodeTree * ntree,bNodeInstanceKey parent_key)1680 static void draw_nodetree(const bContext *C,
1681                           ARegion *region,
1682                           bNodeTree *ntree,
1683                           bNodeInstanceKey parent_key)
1684 {
1685   SpaceNode *snode = CTX_wm_space_node(C);
1686 
1687   node_uiblocks_init(C, ntree);
1688 
1689   node_update_nodetree(C, ntree);
1690   node_draw_nodetree(C, region, snode, ntree, parent_key);
1691 }
1692 
1693 /* shade the parent node group and add a uiBlock to clip mouse events */
draw_group_overlay(const bContext * C,ARegion * region)1694 static void draw_group_overlay(const bContext *C, ARegion *region)
1695 {
1696   View2D *v2d = &region->v2d;
1697   rctf rect = v2d->cur;
1698   uiBlock *block;
1699   float color[4];
1700 
1701   /* shade node groups to separate them visually */
1702   GPU_blend(GPU_BLEND_ALPHA);
1703 
1704   UI_GetThemeColorShadeAlpha4fv(TH_NODE_GROUP, 0, 0, color);
1705   UI_draw_roundbox_corner_set(UI_CNR_NONE);
1706   UI_draw_roundbox_4fv(true, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0, color);
1707   GPU_blend(GPU_BLEND_NONE);
1708 
1709   /* set the block bounds to clip mouse events from underlying nodes */
1710   block = UI_block_begin(C, region, "node tree bounds block", UI_EMBOSS);
1711   UI_block_bounds_set_explicit(block, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1712   UI_block_flag_enable(block, UI_BLOCK_CLIP_EVENTS);
1713   UI_block_end(C, block);
1714 }
1715 
node_draw_space(const bContext * C,ARegion * region)1716 void node_draw_space(const bContext *C, ARegion *region)
1717 {
1718   wmWindow *win = CTX_wm_window(C);
1719   SpaceNode *snode = CTX_wm_space_node(C);
1720   View2D *v2d = &region->v2d;
1721 
1722   /* Setup offscreen buffers. */
1723   GPUViewport *viewport = WM_draw_region_get_viewport(region);
1724 
1725   GPUFrameBuffer *framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(viewport);
1726   GPU_framebuffer_bind_no_srgb(framebuffer_overlay);
1727 
1728   UI_view2d_view_ortho(v2d);
1729   UI_ThemeClearColor(TH_BACK);
1730   GPU_depth_test(GPU_DEPTH_NONE);
1731   GPU_scissor_test(true);
1732 
1733   /* XXX snode->cursor set in coordspace for placing new nodes, used for drawing noodles too */
1734   UI_view2d_region_to_view(&region->v2d,
1735                            win->eventstate->x - region->winrct.xmin,
1736                            win->eventstate->y - region->winrct.ymin,
1737                            &snode->cursor[0],
1738                            &snode->cursor[1]);
1739   snode->cursor[0] /= UI_DPI_FAC;
1740   snode->cursor[1] /= UI_DPI_FAC;
1741 
1742   int grid_levels = UI_GetThemeValueType(TH_NODE_GRID_LEVELS, SPACE_NODE);
1743 
1744   ED_region_draw_cb_draw(C, region, REGION_DRAW_PRE_VIEW);
1745 
1746   /* only set once */
1747   GPU_blend(GPU_BLEND_ALPHA);
1748 
1749   /* nodes */
1750   snode_set_context(C);
1751 
1752   /* draw parent node trees */
1753   if (snode->treepath.last) {
1754     static const int max_depth = 2;
1755     bNodeTreePath *path;
1756     int depth, curdepth;
1757     float center[2];
1758     bNodeTree *ntree;
1759     bNodeLinkDrag *nldrag;
1760     LinkData *linkdata;
1761 
1762     path = snode->treepath.last;
1763 
1764     /* update tree path name (drawn in the bottom left) */
1765     ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id :
1766                                                                           snode->id;
1767 
1768     if (name_id && UNLIKELY(!STREQ(path->node_name, name_id->name + 2))) {
1769       BLI_strncpy(path->node_name, name_id->name + 2, sizeof(path->node_name));
1770     }
1771 
1772     /* current View2D center, will be set temporarily for parent node trees */
1773     UI_view2d_center_get(v2d, &center[0], &center[1]);
1774 
1775     /* store new view center in path and current edittree */
1776     copy_v2_v2(path->view_center, center);
1777     if (snode->edittree) {
1778       copy_v2_v2(snode->edittree->view_center, center);
1779     }
1780 
1781     depth = 0;
1782     while (path->prev && depth < max_depth) {
1783       path = path->prev;
1784       depth++;
1785     }
1786 
1787     /* parent node trees in the background */
1788     for (curdepth = depth; curdepth > 0; path = path->next, curdepth--) {
1789       ntree = path->nodetree;
1790       if (ntree) {
1791         snode_setup_v2d(snode, region, path->view_center);
1792 
1793         draw_nodetree(C, region, ntree, path->parent_key);
1794 
1795         draw_group_overlay(C, region);
1796       }
1797     }
1798 
1799     /* top-level edit tree */
1800     ntree = path->nodetree;
1801     if (ntree) {
1802       snode_setup_v2d(snode, region, center);
1803 
1804       /* grid, uses theme color based on node path depth */
1805       UI_view2d_multi_grid_draw(v2d,
1806                                 (depth > 0 ? TH_NODE_GROUP : TH_GRID),
1807                                 ED_node_grid_size(),
1808                                 NODE_GRID_STEPS,
1809                                 grid_levels);
1810 
1811       /* backdrop */
1812       draw_nodespace_back_pix(C, region, snode, path->parent_key);
1813 
1814       {
1815         float original_proj[4][4];
1816         GPU_matrix_projection_get(original_proj);
1817 
1818         GPU_matrix_push();
1819         GPU_matrix_identity_set();
1820 
1821         wmOrtho2_pixelspace(region->winx, region->winy);
1822 
1823         WM_gizmomap_draw(region->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
1824 
1825         GPU_matrix_pop();
1826         GPU_matrix_projection_set(original_proj);
1827       }
1828 
1829       draw_nodetree(C, region, ntree, path->parent_key);
1830     }
1831 
1832     /* temporary links */
1833     GPU_blend(GPU_BLEND_ALPHA);
1834     GPU_line_smooth(true);
1835     for (nldrag = snode->linkdrag.first; nldrag; nldrag = nldrag->next) {
1836       for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
1837         node_draw_link(v2d, snode, (bNodeLink *)linkdata->data);
1838       }
1839     }
1840     GPU_line_smooth(false);
1841     GPU_blend(GPU_BLEND_NONE);
1842 
1843     if (snode->flag & SNODE_SHOW_GPENCIL) {
1844       /* draw grease-pencil ('canvas' strokes) */
1845       ED_annotation_draw_view2d(C, true);
1846     }
1847   }
1848   else {
1849     /* default grid */
1850     UI_view2d_multi_grid_draw(v2d, TH_GRID, ED_node_grid_size(), NODE_GRID_STEPS, grid_levels);
1851 
1852     /* backdrop */
1853     draw_nodespace_back_pix(C, region, snode, NODE_INSTANCE_KEY_NONE);
1854   }
1855 
1856   ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
1857 
1858   /* reset view matrix */
1859   UI_view2d_view_restore(C);
1860 
1861   if (snode->treepath.last) {
1862     if (snode->flag & SNODE_SHOW_GPENCIL) {
1863       /* draw grease-pencil (screen strokes, and also paintbuffer) */
1864       ED_annotation_draw_view2d(C, false);
1865     }
1866   }
1867 
1868   /* tree path info */
1869   draw_tree_path(snode);
1870 
1871   /* scrollers */
1872   UI_view2d_scrollers_draw(v2d, NULL);
1873 }
1874