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 = ®ion->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 = ®ion->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(®ion->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(®ion->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(®ion->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(®ion->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 = ®ion->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 = ®ion->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 = ®ion->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(®ion->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, ¢er[0], ¢er[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