Blender  V3.3
node_draw.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008 Blender Foundation. All rights reserved. */
3 
9 #include <iomanip>
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "DNA_light_types.h"
14 #include "DNA_linestyle_types.h"
15 #include "DNA_material_types.h"
16 #include "DNA_node_types.h"
17 #include "DNA_screen_types.h"
18 #include "DNA_space_types.h"
19 #include "DNA_text_types.h"
20 #include "DNA_texture_types.h"
21 #include "DNA_world_types.h"
22 
23 #include "BLI_array.hh"
24 #include "BLI_map.hh"
25 #include "BLI_set.hh"
26 #include "BLI_span.hh"
27 #include "BLI_string_ref.hh"
28 #include "BLI_vector.hh"
29 
30 #include "BLT_translation.h"
31 
32 #include "BKE_context.h"
33 #include "BKE_idtype.h"
34 #include "BKE_lib_id.h"
35 #include "BKE_main.h"
36 #include "BKE_node.h"
37 #include "BKE_object.h"
38 
39 #include "DEG_depsgraph.h"
40 
41 #include "BLF_api.h"
42 
43 #include "BIF_glutil.h"
44 
45 #include "GPU_framebuffer.h"
46 #include "GPU_immediate.h"
47 #include "GPU_immediate_util.h"
48 #include "GPU_matrix.h"
49 #include "GPU_state.h"
50 #include "GPU_viewport.h"
51 
52 #include "WM_api.h"
53 #include "WM_types.h"
54 
55 #include "ED_gpencil.h"
56 #include "ED_node.h"
57 #include "ED_screen.h"
58 #include "ED_space_api.h"
59 
60 #include "UI_interface.hh"
61 #include "UI_resources.h"
62 #include "UI_view2d.h"
63 
64 #include "RNA_access.h"
65 #include "RNA_prototypes.h"
66 
68 #include "NOD_node_declaration.hh"
70 
71 #include "FN_field.hh"
72 #include "FN_field_cpp_type.hh"
73 
74 #include "node_intern.hh" /* own include */
75 
76 using blender::GPointer;
80 
81 extern "C" {
82 /* XXX interface.h */
83 extern void ui_draw_dropshadow(
84  const rctf *rct, float radius, float aspect, float alpha, int select);
85 }
86 
88 {
89  return U.widget_unit;
90 }
91 
93 {
94  using namespace blender::ed::space_node;
95 
96  SpaceNode *snode = CTX_wm_space_node(C);
97  if (snode) {
99 
100  id_us_ensure_real(&snode->nodetree->id);
101  }
102 }
103 
104 /* id is supposed to contain a node tree */
106 {
107  if (id) {
108  if (GS(id->name) == ID_NT) {
109  return (bNodeTree *)id;
110  }
111  return ntreeFromID(id);
112  }
113 
114  return nullptr;
115 }
116 
118 {
120  if (id == nullptr || ntree == nullptr) {
121  return;
122  }
123 
124  /* TODO(sergey): With the new dependency graph it should be just enough to only tag ntree itself.
125  * All the users of this tree will have update flushed from the tree. */
126  DEG_id_tag_update(&ntree->id, 0);
127 
128  if (ntree->type == NTREE_SHADER) {
129  DEG_id_tag_update(id, 0);
130 
131  if (GS(id->name) == ID_MA) {
133  }
134  else if (GS(id->name) == ID_LA) {
136  }
137  else if (GS(id->name) == ID_WO) {
139  }
140  }
141  else if (ntree->type == NTREE_COMPOSIT) {
143  }
144  else if (ntree->type == NTREE_TEXTURE) {
145  DEG_id_tag_update(id, 0);
147  }
148  else if (ntree->type == NTREE_GEOMETRY) {
150  }
151  else if (id == &ntree->id) {
152  /* Node groups. */
153  DEG_id_tag_update(id, 0);
154  }
155 }
156 
157 namespace blender::ed::space_node {
158 
159 static bool compare_nodes(const bNode *a, const bNode *b)
160 {
161  /* These tell if either the node or any of the parent nodes is selected.
162  * A selected parent means an unselected node is also in foreground! */
163  bool a_select = (a->flag & NODE_SELECT) != 0, b_select = (b->flag & NODE_SELECT) != 0;
164  bool a_active = (a->flag & NODE_ACTIVE) != 0, b_active = (b->flag & NODE_ACTIVE) != 0;
165 
166  /* If one is an ancestor of the other. */
167  /* XXX there might be a better sorting algorithm for stable topological sort,
168  * this is O(n^2) worst case. */
169  for (bNode *parent = a->parent; parent; parent = parent->parent) {
170  /* If B is an ancestor, it is always behind A. */
171  if (parent == b) {
172  return true;
173  }
174  /* Any selected ancestor moves the node forward. */
175  if (parent->flag & NODE_ACTIVE) {
176  a_active = true;
177  }
178  if (parent->flag & NODE_SELECT) {
179  a_select = true;
180  }
181  }
182  for (bNode *parent = b->parent; parent; parent = parent->parent) {
183  /* If A is an ancestor, it is always behind B. */
184  if (parent == a) {
185  return false;
186  }
187  /* Any selected ancestor moves the node forward. */
188  if (parent->flag & NODE_ACTIVE) {
189  b_active = true;
190  }
191  if (parent->flag & NODE_SELECT) {
192  b_select = true;
193  }
194  }
195 
196  /* One of the nodes is in the background and the other not. */
197  if ((a->flag & NODE_BACKGROUND) && !(b->flag & NODE_BACKGROUND)) {
198  return false;
199  }
200  if (!(a->flag & NODE_BACKGROUND) && (b->flag & NODE_BACKGROUND)) {
201  return true;
202  }
203 
204  /* One has a higher selection state (active > selected > nothing). */
205  if (!b_active && a_active) {
206  return true;
207  }
208  if (!b_select && (a_active || a_select)) {
209  return true;
210  }
211 
212  return false;
213 }
214 
216 {
217  /* Merge sort is the algorithm of choice here. */
218  int totnodes = BLI_listbase_count(&ntree.nodes);
219 
220  int k = 1;
221  while (k < totnodes) {
222  bNode *first_a = (bNode *)ntree.nodes.first;
223  bNode *first_b = first_a;
224 
225  do {
226  /* Set up first_b pointer. */
227  for (int b = 0; b < k && first_b; b++) {
228  first_b = first_b->next;
229  }
230  /* All batches merged? */
231  if (first_b == nullptr) {
232  break;
233  }
234 
235  /* Merge batches. */
236  bNode *node_a = first_a;
237  bNode *node_b = first_b;
238  int a = 0;
239  int b = 0;
240  while (a < k && b < k && node_b) {
241  if (compare_nodes(node_a, node_b) == 0) {
242  node_a = node_a->next;
243  a++;
244  }
245  else {
246  bNode *tmp = node_b;
247  node_b = node_b->next;
248  b++;
249  BLI_remlink(&ntree.nodes, tmp);
250  BLI_insertlinkbefore(&ntree.nodes, node_a, tmp);
251  }
252  }
253 
254  /* Set up first pointers for next batch. */
255  first_b = node_b;
256  for (; b < k; b++) {
257  /* All nodes sorted? */
258  if (first_b == nullptr) {
259  break;
260  }
261  first_b = first_b->next;
262  }
263  first_a = first_b;
264  } while (first_b);
265 
266  k = k << 1;
267  }
268 }
269 
271 {
272  Array<uiBlock *> blocks(nodes.size());
273  /* Add node uiBlocks in drawing order - prevents events going to overlapping nodes. */
274  for (const int i : nodes.index_range()) {
275  const std::string block_name = "node_" + std::string(nodes[i]->name);
276  blocks[i] = UI_block_begin(&C, CTX_wm_region(&C), block_name.c_str(), UI_EMBOSS);
277  /* this cancels events for background nodes */
279  }
280 
281  return blocks;
282 }
283 
284 float2 node_to_view(const bNode &node, const float2 &co)
285 {
286  float2 result;
287  nodeToView(&node, co.x, co.y, &result.x, &result.y);
288  return result * UI_DPI_FAC;
289 }
290 
291 void node_to_updated_rect(const bNode &node, rctf &r_rect)
292 {
293  const float2 xmin_ymax = node_to_view(node, {node.offsetx, node.offsety});
294  r_rect.xmin = xmin_ymax.x;
295  r_rect.ymax = xmin_ymax.y;
296  const float2 xmax_ymin = node_to_view(node,
297  {node.offsetx + node.width, node.offsety - node.height});
298  r_rect.xmax = xmax_ymin.x;
299  r_rect.ymin = xmax_ymin.y;
300 }
301 
303 {
304  const float x = co.x / UI_DPI_FAC;
305  const float y = co.y / UI_DPI_FAC;
306  float2 result;
307  nodeFromView(&node, x, y, &result.x, &result.y);
308  return result;
309 }
310 
314 static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, uiBlock &block)
315 {
316  PointerRNA nodeptr;
317  RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr);
318 
319  const bool node_options = node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS);
320  const bool inputs_first = node.inputs.first &&
321  !(node.outputs.first || (node.flag & NODE_PREVIEW) || node_options);
322 
323  /* Get "global" coordinates. */
324  float2 loc = node_to_view(node, float2(0));
325  /* Round the node origin because text contents are always pixel-aligned. */
326  loc.x = round(loc.x);
327  loc.y = round(loc.y);
328 
329  int dy = loc.y;
330 
331  /* Header. */
332  dy -= NODE_DY;
333 
334  /* Add a little bit of padding above the top socket. */
335  if (node.outputs.first || inputs_first) {
336  dy -= NODE_DYS / 2;
337  }
338 
339  /* Output sockets. */
340  bool add_output_space = false;
341 
342  int buty;
343  LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
344  if (nodeSocketIsHidden(nsock)) {
345  continue;
346  }
347 
348  PointerRNA sockptr;
349  RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr);
350 
351  uiLayout *layout = UI_block_layout(&block,
354  loc.x + NODE_DYS,
355  dy,
357  NODE_DY,
358  0,
359  UI_style_get_dpi());
360 
361  if (node.flag & NODE_MUTED) {
362  uiLayoutSetActive(layout, false);
363  }
364 
365  /* Context pointers for current node and socket. */
366  uiLayoutSetContextPointer(layout, "node", &nodeptr);
367  uiLayoutSetContextPointer(layout, "socket", &sockptr);
368 
369  /* Align output buttons to the right. */
370  uiLayout *row = uiLayoutRow(layout, true);
372  const char *socket_label = nodeSocketLabel(nsock);
373  nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
374 
375  node_socket_add_tooltip(&ntree, &node, nsock, row);
376 
377  UI_block_align_end(&block);
378  UI_block_layout_resolve(&block, nullptr, &buty);
379 
380  /* Ensure minimum socket height in case layout is empty. */
381  buty = min_ii(buty, dy - NODE_DY);
382 
383  /* Round the socket location to stop it from jiggling. */
384  nsock->locx = round(loc.x + NODE_WIDTH(node));
385  nsock->locy = round(dy - NODE_DYS);
386 
387  dy = buty;
388  if (nsock->next) {
389  dy -= NODE_SOCKDY;
390  }
391 
392  add_output_space = true;
393  }
394 
395  if (add_output_space) {
396  dy -= NODE_DY / 4;
397  }
398 
399  node.prvr.xmin = loc.x + NODE_DYS;
400  node.prvr.xmax = loc.x + NODE_WIDTH(node) - NODE_DYS;
401 
402  /* preview rect? */
403  if (node.flag & NODE_PREVIEW) {
404  float aspect = 1.0f;
405 
406  if (node.preview_xsize && node.preview_ysize) {
407  aspect = (float)node.preview_ysize / (float)node.preview_xsize;
408  }
409 
410  dy -= NODE_DYS / 2;
411  node.prvr.ymax = dy;
412 
413  if (aspect <= 1.0f) {
414  node.prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
415  }
416  else {
417  /* Width correction of image. XXX huh? (ton) */
418  float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect;
419 
420  node.prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
421 
422  node.prvr.xmin += 0.5f * dx;
423  node.prvr.xmax -= 0.5f * dx;
424  }
425 
426  dy = node.prvr.ymin - NODE_DYS / 2;
427 
428  /* Make sure that maximums are bigger or equal to minimums. */
429  if (node.prvr.xmax < node.prvr.xmin) {
430  SWAP(float, node.prvr.xmax, node.prvr.xmin);
431  }
432  if (node.prvr.ymax < node.prvr.ymin) {
433  SWAP(float, node.prvr.ymax, node.prvr.ymin);
434  }
435  }
436 
437  /* Buttons rect? */
438  if (node_options) {
439  dy -= NODE_DYS / 2;
440 
441  uiLayout *layout = UI_block_layout(&block,
444  loc.x + NODE_DYS,
445  dy,
447  0,
448  0,
449  UI_style_get_dpi());
450 
451  if (node.flag & NODE_MUTED) {
452  uiLayoutSetActive(layout, false);
453  }
454 
455  uiLayoutSetContextPointer(layout, "node", &nodeptr);
456 
457  node.typeinfo->draw_buttons(layout, (bContext *)&C, &nodeptr);
458 
459  UI_block_align_end(&block);
460  UI_block_layout_resolve(&block, nullptr, &buty);
461 
462  dy = buty - NODE_DYS / 2;
463  }
464 
465  /* Input sockets. */
466  LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
467  if (nodeSocketIsHidden(nsock)) {
468  continue;
469  }
470 
471  PointerRNA sockptr;
472  RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr);
473 
474  /* Add the half the height of a multi-input socket to cursor Y
475  * to account for the increased height of the taller sockets. */
476  float multi_input_socket_offset = 0.0f;
477  if (nsock->flag & SOCK_MULTI_INPUT) {
478  if (nsock->total_inputs > 2) {
479  multi_input_socket_offset = (nsock->total_inputs - 2) * NODE_MULTI_INPUT_LINK_GAP;
480  }
481  }
482  dy -= multi_input_socket_offset * 0.5f;
483 
484  uiLayout *layout = UI_block_layout(&block,
487  loc.x + NODE_DYS,
488  dy,
490  NODE_DY,
491  0,
492  UI_style_get_dpi());
493 
494  if (node.flag & NODE_MUTED) {
495  uiLayoutSetActive(layout, false);
496  }
497 
498  /* Context pointers for current node and socket. */
499  uiLayoutSetContextPointer(layout, "node", &nodeptr);
500  uiLayoutSetContextPointer(layout, "socket", &sockptr);
501 
502  uiLayout *row = uiLayoutRow(layout, true);
503 
504  const char *socket_label = nodeSocketLabel(nsock);
505  nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
506 
507  node_socket_add_tooltip(&ntree, &node, nsock, row);
508 
509  UI_block_align_end(&block);
510  UI_block_layout_resolve(&block, nullptr, &buty);
511 
512  /* Ensure minimum socket height in case layout is empty. */
513  buty = min_ii(buty, dy - NODE_DY);
514 
515  nsock->locx = loc.x;
516  /* Round the socket vertical position to stop it from jiggling. */
517  nsock->locy = round(dy - NODE_DYS);
518 
519  dy = buty - multi_input_socket_offset * 0.5;
520  if (nsock->next) {
521  dy -= NODE_SOCKDY;
522  }
523  }
524 
525  /* Little bit of space in end. */
526  if (node.inputs.first || (node.flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0) {
527  dy -= NODE_DYS / 2;
528  }
529 
530  node.totr.xmin = loc.x;
531  node.totr.xmax = loc.x + NODE_WIDTH(node);
532  node.totr.ymax = loc.y;
533  node.totr.ymin = min_ff(dy, loc.y - 2 * NODE_DY);
534 
535  /* Set the block bounds to clip mouse events from underlying nodes.
536  * Add a margin for sockets on each side. */
538  node.totr.xmin - NODE_SOCKSIZE,
539  node.totr.ymin,
540  node.totr.xmax + NODE_SOCKSIZE,
541  node.totr.ymax);
542 }
543 
547 static void node_update_hidden(bNode &node, uiBlock &block)
548 {
549  int totin = 0, totout = 0;
550 
551  /* Get "global" coordinates. */
552  float2 loc = node_to_view(node, float2(0));
553  /* Round the node origin because text contents are always pixel-aligned. */
554  loc.x = round(loc.x);
555  loc.y = round(loc.y);
556 
557  /* Calculate minimal radius. */
558  LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
559  if (!nodeSocketIsHidden(nsock)) {
560  totin++;
561  }
562  }
563  LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
564  if (!nodeSocketIsHidden(nsock)) {
565  totout++;
566  }
567  }
568 
569  float hiddenrad = HIDDEN_RAD;
570  float tot = MAX2(totin, totout);
571  if (tot > 4) {
572  hiddenrad += 5.0f * (float)(tot - 4);
573  }
574 
575  node.totr.xmin = loc.x;
576  node.totr.xmax = loc.x + max_ff(NODE_WIDTH(node), 2 * hiddenrad);
577  node.totr.ymax = loc.y + (hiddenrad - 0.5f * NODE_DY);
578  node.totr.ymin = node.totr.ymax - 2 * hiddenrad;
579 
580  /* Output sockets. */
581  float rad = (float)M_PI / (1.0f + (float)totout);
582  float drad = rad;
583 
584  LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
585  if (!nodeSocketIsHidden(nsock)) {
586  /* Round the socket location to stop it from jiggling. */
587  nsock->locx = round(node.totr.xmax - hiddenrad + sinf(rad) * hiddenrad);
588  nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
589  rad += drad;
590  }
591  }
592 
593  /* Input sockets. */
594  rad = drad = -(float)M_PI / (1.0f + (float)totin);
595 
596  LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
597  if (!nodeSocketIsHidden(nsock)) {
598  /* Round the socket location to stop it from jiggling. */
599  nsock->locx = round(node.totr.xmin + hiddenrad + sinf(rad) * hiddenrad);
600  nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
601  rad += drad;
602  }
603  }
604 
605  /* Set the block bounds to clip mouse events from underlying nodes.
606  * Add a margin for sockets on each side. */
608  node.totr.xmin - NODE_SOCKSIZE,
609  node.totr.ymin,
610  node.totr.xmax + NODE_SOCKSIZE,
611  node.totr.ymax);
612 }
613 
614 static int node_get_colorid(const bNode &node)
615 {
616  const int nclass = (node.typeinfo->ui_class == nullptr) ? node.typeinfo->nclass :
617  node.typeinfo->ui_class(&node);
618  switch (nclass) {
619  case NODE_CLASS_INPUT:
620  return TH_NODE_INPUT;
621  case NODE_CLASS_OUTPUT:
622  return (node.flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE;
624  return TH_NODE_CONVERTER;
625  case NODE_CLASS_OP_COLOR:
626  return TH_NODE_COLOR;
628  return TH_NODE_VECTOR;
630  return TH_NODE_FILTER;
631  case NODE_CLASS_GROUP:
632  return TH_NODE_GROUP;
634  return TH_NODE_INTERFACE;
635  case NODE_CLASS_MATTE:
636  return TH_NODE_MATTE;
637  case NODE_CLASS_DISTORT:
638  return TH_NODE_DISTORT;
639  case NODE_CLASS_TEXTURE:
640  return TH_NODE_TEXTURE;
641  case NODE_CLASS_SHADER:
642  return TH_NODE_SHADER;
643  case NODE_CLASS_SCRIPT:
644  return TH_NODE_SCRIPT;
645  case NODE_CLASS_PATTERN:
646  return TH_NODE_PATTERN;
647  case NODE_CLASS_LAYOUT:
648  return TH_NODE_LAYOUT;
649  case NODE_CLASS_GEOMETRY:
650  return TH_NODE_GEOMETRY;
652  return TH_NODE_ATTRIBUTE;
653  default:
654  return TH_NODE;
655  }
656 }
657 
658 static void node_draw_mute_line(const bContext &C,
659  const View2D &v2d,
660  const SpaceNode &snode,
661  const bNode &node)
662 {
664 
665  LISTBASE_FOREACH (const bNodeLink *, link, &node.internal_links) {
666  if (!nodeLinkIsHidden(link)) {
667  node_draw_link_bezier(C, v2d, snode, *link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE, false);
668  }
669  }
670 
672 }
673 
674 static void node_socket_draw(const bNodeSocket &sock,
675  const float color[4],
676  const float color_outline[4],
677  float size,
678  int locx,
679  int locy,
680  uint pos_id,
681  uint col_id,
682  uint shape_id,
683  uint size_id,
684  uint outline_col_id)
685 {
686  int flags;
687 
688  /* Set shape flags. */
689  switch (sock.display_shape) {
693  break;
697  break;
698  default:
702  break;
703  }
704 
705  if (ELEM(sock.display_shape,
710  }
711 
712  immAttr4fv(col_id, color);
713  immAttr1u(shape_id, flags);
714  immAttr1f(size_id, size);
715  immAttr4fv(outline_col_id, color_outline);
716  immVertex2f(pos_id, locx, locy);
717 }
718 
719 static void node_socket_draw_multi_input(const float color[4],
720  const float color_outline[4],
721  const float width,
722  const float height,
723  const int locx,
724  const int locy)
725 {
726  /* The other sockets are drawn with the keyframe shader. There, the outline has a base thickness
727  * that can be varied but always scales with the size the socket is drawn at. Using `U.dpi_fac`
728  * has the same effect here. It scales the outline correctly across different screen DPI's
729  * and UI scales without being affected by the 'line-width'. */
730  const float outline_width = NODE_SOCK_OUTLINE_SCALE * U.dpi_fac;
731 
732  /* UI_draw_roundbox draws the outline on the outer side, so compensate for the outline width. */
733  const rctf rect = {
734  locx - width + outline_width * 0.5f,
735  locx + width - outline_width * 0.5f,
736  locy - height + outline_width * 0.5f,
737  locy + height - outline_width * 0.5f,
738  };
739 
742  &rect, color, nullptr, 1.0f, color_outline, outline_width, width - outline_width * 0.5f);
743 }
744 
745 static const float virtual_node_socket_outline_color[4] = {0.5, 0.5, 0.5, 1.0};
746 
747 static void node_socket_outline_color_get(const bool selected,
748  const int socket_type,
749  float r_outline_color[4])
750 {
751  if (selected) {
752  UI_GetThemeColor4fv(TH_ACTIVE, r_outline_color);
753  }
754  else if (socket_type == SOCK_CUSTOM) {
755  /* Until there is a better place for per socket color,
756  * the outline color for virtual sockets is set here. */
758  }
759  else {
760  UI_GetThemeColor4fv(TH_WIRE, r_outline_color);
761  }
762 }
763 
765  const bNodeTree &ntree,
766  PointerRNA &node_ptr,
767  const bNodeSocket &sock,
768  float r_color[4])
769 {
770  PointerRNA ptr;
771  BLI_assert(RNA_struct_is_a(node_ptr.type, &RNA_Node));
772  RNA_pointer_create((ID *)&ntree, &RNA_NodeSocket, &const_cast<bNodeSocket &>(sock), &ptr);
773 
774  sock.typeinfo->draw_color((bContext *)&C, &ptr, &node_ptr, r_color);
775 }
776 
781 };
782 
783 static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss)
784 {
785  auto id_to_inspection_string = [&](const ID *id, const short idcode) {
786  ss << (id ? id->name + 2 : TIP_("None")) << " (" << TIP_(BKE_idtype_idcode_to_name(idcode))
787  << ")";
788  };
789 
790  const CPPType &type = *value.type();
791  const void *buffer = value.get();
792  if (type.is<Object *>()) {
793  id_to_inspection_string(*static_cast<const ID *const *>(buffer), ID_OB);
794  }
795  else if (type.is<Material *>()) {
796  id_to_inspection_string(*static_cast<const ID *const *>(buffer), ID_MA);
797  }
798  else if (type.is<Tex *>()) {
799  id_to_inspection_string(*static_cast<const ID *const *>(buffer), ID_TE);
800  }
801  else if (type.is<Image *>()) {
802  id_to_inspection_string(*static_cast<const ID *const *>(buffer), ID_IM);
803  }
804  else if (type.is<Collection *>()) {
805  id_to_inspection_string(*static_cast<const ID *const *>(buffer), ID_GR);
806  }
807  else if (type.is<int>()) {
808  ss << *(int *)buffer << TIP_(" (Integer)");
809  }
810  else if (type.is<float>()) {
811  ss << *(float *)buffer << TIP_(" (Float)");
812  }
813  else if (type.is<blender::float3>()) {
814  ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
815  }
816  else if (type.is<bool>()) {
817  ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
818  }
819  else if (type.is<std::string>()) {
820  ss << *(std::string *)buffer << TIP_(" (String)");
821  }
822 }
823 
825  std::stringstream &ss)
826 {
827  const CPPType &type = value_log.type();
828  const GField &field = value_log.field();
829  const Span<std::string> input_tooltips = value_log.input_tooltips();
830 
831  if (input_tooltips.is_empty()) {
832  if (field) {
836  type.destruct(buffer);
837  }
838  else {
839  /* Constant values should always be logged. */
841  ss << "Value has not been logged";
842  }
843  }
844  else {
845  if (type.is<int>()) {
846  ss << TIP_("Integer field");
847  }
848  else if (type.is<float>()) {
849  ss << TIP_("Float field");
850  }
851  else if (type.is<blender::float3>()) {
852  ss << TIP_("Vector field");
853  }
854  else if (type.is<bool>()) {
855  ss << TIP_("Boolean field");
856  }
857  else if (type.is<std::string>()) {
858  ss << TIP_("String field");
859  }
860  else if (type.is<blender::ColorGeometry4f>()) {
861  ss << TIP_("Color field");
862  }
863  ss << TIP_(" based on:\n");
864 
865  for (const int i : input_tooltips.index_range()) {
866  const blender::StringRef tooltip = input_tooltips[i];
867  ss << "\u2022 " << tooltip;
868  if (i < input_tooltips.size() - 1) {
869  ss << ".\n";
870  }
871  }
872  }
873 }
874 
876  std::stringstream &ss,
877  const nodes::decl::Geometry *geometry)
878 {
879  Span<GeometryComponentType> component_types = value_log.component_types();
880  if (component_types.is_empty()) {
881  ss << TIP_("Empty Geometry");
882  return;
883  }
884 
885  auto to_string = [](int value) {
886  char str[16];
888  return std::string(str);
889  };
890 
891  ss << TIP_("Geometry:\n");
892  for (GeometryComponentType type : component_types) {
893  const char *line_end = (type == component_types.last()) ? "" : ".\n";
894  switch (type) {
896  const geo_log::GeometryValueLog::MeshInfo &mesh_info = *value_log.mesh_info;
897  char line[256];
898  BLI_snprintf(line,
899  sizeof(line),
900  TIP_("\u2022 Mesh: %s vertices, %s edges, %s faces"),
901  to_string(mesh_info.verts_num).c_str(),
902  to_string(mesh_info.edges_num).c_str(),
903  to_string(mesh_info.faces_num).c_str());
904  ss << line << line_end;
905  break;
906  }
908  const geo_log::GeometryValueLog::PointCloudInfo &pointcloud_info =
909  *value_log.pointcloud_info;
910  char line[256];
911  BLI_snprintf(line,
912  sizeof(line),
913  TIP_("\u2022 Point Cloud: %s points"),
914  to_string(pointcloud_info.points_num).c_str());
915  ss << line << line_end;
916  break;
917  }
919  const geo_log::GeometryValueLog::CurveInfo &curve_info = *value_log.curve_info;
920  char line[256];
921  BLI_snprintf(line,
922  sizeof(line),
923  TIP_("\u2022 Curve: %s splines"),
924  to_string(curve_info.splines_num).c_str());
925  ss << line << line_end;
926  break;
927  }
929  const geo_log::GeometryValueLog::InstancesInfo &instances_info = *value_log.instances_info;
930  char line[256];
931  BLI_snprintf(line,
932  sizeof(line),
933  TIP_("\u2022 Instances: %s"),
934  to_string(instances_info.instances_num).c_str());
935  ss << line << line_end;
936  break;
937  }
939  ss << TIP_("\u2022 Volume") << line_end;
940  break;
941  }
943  if (value_log.edit_data_info.has_value()) {
944  const geo_log::GeometryValueLog::EditDataInfo &edit_info = *value_log.edit_data_info;
945  char line[256];
946  BLI_snprintf(line,
947  sizeof(line),
948  TIP_("\u2022 Edit Curves: %s, %s"),
949  edit_info.has_deformed_positions ? TIP_("positions") : TIP_("no positions"),
950  edit_info.has_deform_matrices ? TIP_("matrices") : TIP_("no matrices"));
951  ss << line << line_end;
952  }
953  break;
954  }
955  }
956  }
957 
958  /* If the geometry declaration is null, as is the case for input to group output,
959  * or it is an output socket don't show supported types. */
960  if (geometry == nullptr || geometry->in_out() == SOCK_OUT) {
961  return;
962  }
963 
964  Span<GeometryComponentType> supported_types = geometry->supported_types();
965  if (supported_types.is_empty()) {
966  ss << ".\n\n" << TIP_("Supported: All Types");
967  return;
968  }
969 
970  ss << ".\n\n" << TIP_("Supported: ");
971  for (GeometryComponentType type : supported_types) {
972  switch (type) {
974  ss << TIP_("Mesh");
975  break;
976  }
978  ss << TIP_("Point Cloud");
979  break;
980  }
982  ss << TIP_("Curve");
983  break;
984  }
986  ss << TIP_("Instances");
987  break;
988  }
990  ss << TIP_("Volume");
991  break;
992  }
994  break;
995  }
996  }
997  ss << ((type == supported_types.last()) ? "" : ", ");
998  }
999 }
1000 
1001 static std::optional<std::string> create_socket_inspection_string(bContext *C,
1002  bNode &node,
1003  bNodeSocket &socket)
1004 {
1005  SpaceNode *snode = CTX_wm_space_node(C);
1006  if (snode == nullptr) {
1007  return {};
1008  };
1009 
1011  *snode, node, socket);
1012  if (socket_log == nullptr) {
1013  return {};
1014  }
1015  const geo_log::ValueLog *value_log = socket_log->value();
1016  if (value_log == nullptr) {
1017  return {};
1018  }
1019 
1020  std::stringstream ss;
1021  if (const geo_log::GenericValueLog *generic_value_log =
1022  dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
1023  create_inspection_string_for_generic_value(generic_value_log->value(), ss);
1024  }
1025  if (const geo_log::GFieldValueLog *gfield_value_log =
1026  dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) {
1027  create_inspection_string_for_gfield(*gfield_value_log, ss);
1028  }
1029  else if (const geo_log::GeometryValueLog *geo_value_log =
1030  dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
1032  *geo_value_log,
1033  ss,
1034  dynamic_cast<const nodes::decl::Geometry *>(socket.runtime->declaration));
1035  }
1036 
1037  return ss.str();
1038 }
1039 
1041 {
1042  if (ntree->type == NTREE_GEOMETRY) {
1043  return true;
1044  }
1045 
1046  if (socket->runtime->declaration != nullptr) {
1047  const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration;
1048  return !socket_decl.description().is_empty();
1049  }
1050 
1051  return false;
1052 }
1053 
1055  bNodeTree *ntree,
1056  bNode *node,
1057  bNodeSocket *socket)
1058 {
1059  std::stringstream output;
1060  if (socket->runtime->declaration != nullptr) {
1061  const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration;
1062  blender::StringRef description = socket_decl.description();
1063  if (!description.is_empty()) {
1064  output << TIP_(description.data());
1065  }
1066  }
1067 
1068  if (ntree->type == NTREE_GEOMETRY) {
1069  if (!output.str().empty()) {
1070  output << ".\n\n";
1071  }
1072 
1073  std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
1074  C, *node, *socket);
1075  if (socket_inspection_str.has_value()) {
1076  output << *socket_inspection_str;
1077  }
1078  else {
1079  output << TIP_("The socket value has not been computed yet");
1080  }
1081  }
1082 
1083  if (output.str().empty()) {
1084  output << nodeSocketLabel(socket);
1085  }
1086 
1087  return BLI_strdup(output.str().c_str());
1088 }
1089 
1091 {
1092  if (!node_socket_has_tooltip(ntree, sock)) {
1093  return;
1094  }
1095 
1096  SocketTooltipData *data = MEM_cnew<SocketTooltipData>(__func__);
1097  data->ntree = ntree;
1098  data->node = node;
1099  data->socket = sock;
1100 
1102  layout,
1103  [](bContext *C, void *argN, const char *UNUSED(tip)) {
1104  SocketTooltipData *data = static_cast<SocketTooltipData *>(argN);
1105  return node_socket_get_tooltip(C, data->ntree, data->node, data->socket);
1106  },
1107  data,
1108  MEM_dupallocN,
1109  MEM_freeN);
1110 }
1111 
1113  bNodeTree &ntree,
1114  PointerRNA &node_ptr,
1115  uiBlock &block,
1116  bNodeSocket &sock,
1117  const uint pos_id,
1118  const uint col_id,
1119  const uint shape_id,
1120  const uint size_id,
1121  const uint outline_col_id,
1122  const float size,
1123  const bool selected)
1124 {
1125  float color[4];
1126  float outline_color[4];
1127 
1128  node_socket_color_get(C, ntree, node_ptr, sock, color);
1129  node_socket_outline_color_get(selected, sock.type, outline_color);
1130 
1131  node_socket_draw(sock,
1132  color,
1133  outline_color,
1134  size,
1135  sock.locx,
1136  sock.locy,
1137  pos_id,
1138  col_id,
1139  shape_id,
1140  size_id,
1141  outline_col_id);
1142 
1143  if (!node_socket_has_tooltip(&ntree, &sock)) {
1144  return;
1145  }
1146 
1147  /* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible
1148  * button on top of them for the tooltip. */
1149  const eUIEmbossType old_emboss = UI_block_emboss_get(&block);
1151  uiBut *but = uiDefIconBut(&block,
1152  UI_BTYPE_BUT,
1153  0,
1154  ICON_NONE,
1155  sock.locx - size / 2,
1156  sock.locy - size / 2,
1157  size,
1158  size,
1159  nullptr,
1160  0,
1161  0,
1162  0,
1163  0,
1164  nullptr);
1165 
1167  data->ntree = &ntree;
1168  data->node = (bNode *)node_ptr.data;
1169  data->socket = &sock;
1170 
1172  but,
1173  [](bContext *C, void *argN, const char *UNUSED(tip)) {
1175  return node_socket_get_tooltip(C, data->ntree, data->node, data->socket);
1176  },
1177  data,
1178  MEM_freeN);
1179  /* Disable the button so that clicks on it are ignored the link operator still works. */
1181  UI_block_emboss_set(&block, old_emboss);
1182 }
1183 
1184 } // namespace blender::ed::space_node
1185 
1186 void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
1187 {
1188  using namespace blender::ed::space_node;
1189 
1190  const float size = NODE_SOCKSIZE_DRAW_MULIPLIER * NODE_SOCKSIZE * scale;
1191  rcti draw_rect = *rect;
1192  float outline_color[4] = {0};
1193 
1194  node_socket_outline_color_get(sock->flag & SELECT, sock->type, outline_color);
1195 
1196  BLI_rcti_resize(&draw_rect, size, size);
1197 
1201  uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
1203  uint outline_col_id = GPU_vertformat_attr_add(
1204  format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1205 
1208  GPU_program_point_size(true);
1209 
1211  immUniform1f("outline_scale", NODE_SOCK_OUTLINE_SCALE);
1212  immUniform2f("ViewportSize", -1.0f, -1.0f);
1213 
1214  /* Single point. */
1216  node_socket_draw(*sock,
1217  color,
1218  outline_color,
1219  BLI_rcti_size_y(&draw_rect),
1220  BLI_rcti_cent_x(&draw_rect),
1221  BLI_rcti_cent_y(&draw_rect),
1222  pos_id,
1223  col_id,
1224  shape_id,
1225  size_id,
1226  outline_col_id);
1227  immEnd();
1228 
1229  immUnbindProgram();
1230  GPU_program_point_size(false);
1231 
1232  /* Restore. */
1233  GPU_blend(state);
1234 }
1235 
1236 namespace blender::ed::space_node {
1237 
1238 /* ************** Socket callbacks *********** */
1239 
1241 {
1244 
1246 
1247  /* Drawing the checkerboard. */
1248  const float checker_dark = UI_ALPHA_CHECKER_DARK / 255.0f;
1249  const float checker_light = UI_ALPHA_CHECKER_LIGHT / 255.0f;
1250  immUniform4f("color1", checker_dark, checker_dark, checker_dark, 1.0f);
1251  immUniform4f("color2", checker_light, checker_light, checker_light, 1.0f);
1252  immUniform1i("size", 8);
1253  immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1254  immUnbindProgram();
1255 }
1256 
1257 /* Not a callback. */
1259 {
1260  float xrect = BLI_rctf_size_x(prv);
1261  float yrect = BLI_rctf_size_y(prv);
1262  float xscale = xrect / ((float)preview->xsize);
1263  float yscale = yrect / ((float)preview->ysize);
1264  float scale;
1265 
1266  /* Uniform scale and offset. */
1267  rctf draw_rect = *prv;
1268  if (xscale < yscale) {
1269  float offset = 0.5f * (yrect - ((float)preview->ysize) * xscale);
1270  draw_rect.ymin += offset;
1271  draw_rect.ymax -= offset;
1272  scale = xscale;
1273  }
1274  else {
1275  float offset = 0.5f * (xrect - ((float)preview->xsize) * yscale);
1276  draw_rect.xmin += offset;
1277  draw_rect.xmax -= offset;
1278  scale = yscale;
1279  }
1280 
1281  node_draw_preview_background(&draw_rect);
1282 
1284  /* Premul graphics. */
1286 
1289  draw_rect.xmin,
1290  draw_rect.ymin,
1291  preview->xsize,
1292  preview->ysize,
1293  GPU_RGBA8,
1294  true,
1295  preview->rect,
1296  scale,
1297  scale,
1298  nullptr);
1299 
1301 
1305  imm_draw_box_wire_2d(pos, draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
1306  immUnbindProgram();
1307 }
1308 
1309 /* Common handle function for operator buttons that need to select the node first. */
1310 static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv)
1311 {
1312  bNode *node = (bNode *)node_argv;
1313  const char *opname = (const char *)op_argv;
1314 
1315  /* Select & activate only the button's node. */
1317 
1318  WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
1319 }
1320 
1321 static void node_draw_shadow(const SpaceNode &snode,
1322  const bNode &node,
1323  const float radius,
1324  const float alpha)
1325 {
1326  const rctf &rct = node.totr;
1328  ui_draw_dropshadow(&rct, radius, snode.runtime->aspect, alpha, node.flag & SELECT);
1329 }
1330 
1331 static void node_draw_sockets(const View2D &v2d,
1332  const bContext &C,
1333  bNodeTree &ntree,
1334  bNode &node,
1335  uiBlock &block,
1336  const bool draw_outputs,
1337  const bool select_all)
1338 {
1339  const uint total_input_len = BLI_listbase_count(&node.inputs);
1340  const uint total_output_len = BLI_listbase_count(&node.outputs);
1341 
1342  if (total_input_len + total_output_len == 0) {
1343  return;
1344  }
1345 
1346  PointerRNA node_ptr;
1347  RNA_pointer_create((ID *)&ntree, &RNA_Node, &node, &node_ptr);
1348 
1349  bool selected = false;
1350 
1354  uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
1356  uint outline_col_id = GPU_vertformat_attr_add(
1357  format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1358 
1360  GPU_program_point_size(true);
1362  immUniform1f("outline_scale", NODE_SOCK_OUTLINE_SCALE);
1363  immUniform2f("ViewportSize", -1.0f, -1.0f);
1364 
1365  /* Set handle size. */
1366  const float socket_draw_size = NODE_SOCKSIZE * NODE_SOCKSIZE_DRAW_MULIPLIER;
1367  float scale;
1368  UI_view2d_scale_get(&v2d, &scale, nullptr);
1369  scale *= socket_draw_size;
1370 
1371  if (!select_all) {
1372  immBeginAtMost(GPU_PRIM_POINTS, total_input_len + total_output_len);
1373  }
1374 
1375  /* Socket inputs. */
1376  short selected_input_len = 0;
1377  LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
1378  if (nodeSocketIsHidden(sock)) {
1379  continue;
1380  }
1381  if (select_all || (sock->flag & SELECT)) {
1382  if (!(sock->flag & SOCK_MULTI_INPUT)) {
1383  /* Don't add multi-input sockets here since they are drawn in a different batch. */
1384  selected_input_len++;
1385  }
1386  continue;
1387  }
1388  /* Don't draw multi-input sockets here since they are drawn in a different batch. */
1389  if (sock->flag & SOCK_MULTI_INPUT) {
1390  continue;
1391  }
1392 
1394  ntree,
1395  node_ptr,
1396  block,
1397  *sock,
1398  pos_id,
1399  col_id,
1400  shape_id,
1401  size_id,
1402  outline_col_id,
1403  scale,
1404  selected);
1405  }
1406 
1407  /* Socket outputs. */
1408  short selected_output_len = 0;
1409  if (draw_outputs) {
1410  LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
1411  if (nodeSocketIsHidden(sock)) {
1412  continue;
1413  }
1414  if (select_all || (sock->flag & SELECT)) {
1415  selected_output_len++;
1416  continue;
1417  }
1418 
1420  ntree,
1421  node_ptr,
1422  block,
1423  *sock,
1424  pos_id,
1425  col_id,
1426  shape_id,
1427  size_id,
1428  outline_col_id,
1429  scale,
1430  selected);
1431  }
1432  }
1433 
1434  if (!select_all) {
1435  immEnd();
1436  }
1437 
1438  /* Go back and draw selected sockets. */
1439  if (selected_input_len + selected_output_len > 0) {
1440  /* Outline for selected sockets. */
1441 
1442  selected = true;
1443 
1444  immBegin(GPU_PRIM_POINTS, selected_input_len + selected_output_len);
1445 
1446  if (selected_input_len) {
1447  /* Socket inputs. */
1448  LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
1449  if (nodeSocketIsHidden(sock)) {
1450  continue;
1451  }
1452  /* Don't draw multi-input sockets here since they are drawn in a different batch. */
1453  if (sock->flag & SOCK_MULTI_INPUT) {
1454  continue;
1455  }
1456  if (select_all || (sock->flag & SELECT)) {
1458  ntree,
1459  node_ptr,
1460  block,
1461  *sock,
1462  pos_id,
1463  col_id,
1464  shape_id,
1465  size_id,
1466  outline_col_id,
1467  scale,
1468  selected);
1469  if (--selected_input_len == 0) {
1470  break; /* Stop as soon as last one is drawn. */
1471  }
1472  }
1473  }
1474  }
1475 
1476  if (selected_output_len) {
1477  /* Socket outputs. */
1478  LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
1479  if (nodeSocketIsHidden(sock)) {
1480  continue;
1481  }
1482  if (select_all || (sock->flag & SELECT)) {
1484  ntree,
1485  node_ptr,
1486  block,
1487  *sock,
1488  pos_id,
1489  col_id,
1490  shape_id,
1491  size_id,
1492  outline_col_id,
1493  scale,
1494  selected);
1495  if (--selected_output_len == 0) {
1496  break; /* Stop as soon as last one is drawn. */
1497  }
1498  }
1499  }
1500  }
1501 
1502  immEnd();
1503  }
1504 
1505  immUnbindProgram();
1506 
1507  GPU_program_point_size(false);
1509 
1510  /* Draw multi-input sockets after the others because they are drawn with `UI_draw_roundbox`
1511  * rather than with `GL_POINT`. */
1512  LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
1513  if (nodeSocketIsHidden(socket)) {
1514  continue;
1515  }
1516  if (!(socket->flag & SOCK_MULTI_INPUT)) {
1517  continue;
1518  }
1519 
1520  const bool is_node_hidden = (node.flag & NODE_HIDDEN);
1521  const float width = 0.5f * socket_draw_size;
1522  float height = is_node_hidden ? width : node_socket_calculate_height(*socket) - width;
1523 
1524  float color[4];
1525  float outline_color[4];
1526  node_socket_color_get(C, ntree, node_ptr, *socket, color);
1527  node_socket_outline_color_get(socket->flag & SELECT, socket->type, outline_color);
1528 
1529  node_socket_draw_multi_input(color, outline_color, width, height, socket->locx, socket->locy);
1530  }
1531 }
1532 
1534 {
1535  switch (type) {
1537  return ICON_ERROR;
1538  case geo_log::NodeWarningType::Warning:
1539  return ICON_ERROR;
1541  return ICON_INFO;
1542  }
1543 
1544  BLI_assert(false);
1545  return ICON_ERROR;
1546 }
1547 
1549 {
1550  switch (type) {
1552  return 3;
1553  case geo_log::NodeWarningType::Warning:
1554  return 2;
1556  return 1;
1557  }
1558 
1559  BLI_assert(false);
1560  return 0;
1561 }
1562 
1564 {
1565  uint8_t highest_priority = 0;
1567  for (const geo_log::NodeWarning &warning : warnings) {
1568  const uint8_t priority = node_error_type_priority(warning.type);
1569  if (priority > highest_priority) {
1570  highest_priority = priority;
1571  highest_priority_type = warning.type;
1572  }
1573  }
1574  return highest_priority_type;
1575 }
1576 
1579 };
1580 
1581 static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
1582 {
1584 
1585  std::string complete_string;
1586 
1587  for (const geo_log::NodeWarning &warning : data.warnings.drop_back(1)) {
1588  complete_string += warning.message;
1589  /* Adding the period is not ideal for multi-line messages, but it is consistent
1590  * with other tooltip implementations in Blender, so it is added here. */
1591  complete_string += '.';
1592  complete_string += '\n';
1593  }
1594 
1595  /* Let the tooltip system automatically add the last period. */
1596  complete_string += data.warnings.last().message;
1597 
1598  return BLI_strdupn(complete_string.c_str(), complete_string.size());
1599 }
1600 
1601 #define NODE_HEADER_ICON_SIZE (0.8f * U.widget_unit)
1602 
1604  const bContext &C, bNode &node, uiBlock &block, const rctf &rect, float &icon_offset)
1605 {
1606  SpaceNode *snode = CTX_wm_space_node(&C);
1608  node);
1609  if (node_log == nullptr) {
1610  return;
1611  }
1612 
1613  Span<geo_log::NodeWarning> warnings = node_log->warnings();
1614 
1615  if (warnings.is_empty()) {
1616  return;
1617  }
1618 
1620  sizeof(NodeErrorsTooltipData), __func__);
1621  tooltip_data->warnings = warnings;
1622 
1623  const geo_log::NodeWarningType display_type = node_error_highest_priority(warnings);
1624 
1625  icon_offset -= NODE_HEADER_ICON_SIZE;
1627  uiBut *but = uiDefIconBut(&block,
1628  UI_BTYPE_BUT,
1629  0,
1630  node_error_type_to_icon(display_type),
1631  icon_offset,
1632  rect.ymax - NODE_DY,
1634  UI_UNIT_Y,
1635  nullptr,
1636  0,
1637  0,
1638  0,
1639  0,
1640  nullptr);
1642  UI_block_emboss_set(&block, UI_EMBOSS);
1643 }
1644 
1646  const SpaceNode &snode,
1647  std::chrono::microseconds &exec_time,
1648  int &node_count)
1649 {
1650  if (node.type == NODE_GROUP) {
1652  snode);
1653  if (root_tree_log == nullptr) {
1654  return;
1655  }
1656  const geo_log::TreeLog *tree_log = root_tree_log->lookup_child_log(node.name);
1657  if (tree_log == nullptr) {
1658  return;
1659  }
1660  tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
1661  exec_time += node_log.execution_time();
1662  node_count++;
1663  });
1664  }
1665  else {
1667  snode, node);
1668  if (node_log) {
1669  exec_time += node_log->execution_time();
1670  node_count++;
1671  }
1672  }
1673 }
1674 
1675 static std::chrono::microseconds node_get_execution_time(const bNodeTree &ntree,
1676  const bNode &node,
1677  const SpaceNode &snode,
1678  int &node_count)
1679 {
1680  std::chrono::microseconds exec_time = std::chrono::microseconds::zero();
1681  if (node.type == NODE_GROUP_OUTPUT) {
1683  snode);
1684 
1685  if (tree_log == nullptr) {
1686  return exec_time;
1687  }
1688  tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
1689  exec_time += node_log.execution_time();
1690  node_count++;
1691  });
1692  }
1693  else if (node.type == NODE_FRAME) {
1694  /* Could be cached in the future if this recursive code turns out to be slow. */
1695  LISTBASE_FOREACH (bNode *, tnode, &ntree.nodes) {
1696  if (tnode->parent != &node) {
1697  continue;
1698  }
1699 
1700  if (tnode->type == NODE_FRAME) {
1701  exec_time += node_get_execution_time(ntree, *tnode, snode, node_count);
1702  }
1703  else {
1704  get_exec_time_other_nodes(*tnode, snode, exec_time, node_count);
1705  }
1706  }
1707  }
1708  else {
1709  get_exec_time_other_nodes(node, snode, exec_time, node_count);
1710  }
1711  return exec_time;
1712 }
1713 
1714 static std::string node_get_execution_time_label(const SpaceNode &snode, const bNode &node)
1715 {
1716  int node_count = 0;
1717  std::chrono::microseconds exec_time = node_get_execution_time(
1718  *snode.edittree, node, snode, node_count);
1719 
1720  if (node_count == 0) {
1721  return std::string("");
1722  }
1723 
1724  uint64_t exec_time_us = exec_time.count();
1725 
1726  /* Don't show time if execution time is 0 microseconds. */
1727  if (exec_time_us == 0) {
1728  return std::string("-");
1729  }
1730  if (exec_time_us < 100) {
1731  return std::string("< 0.1 ms");
1732  }
1733 
1734  int precision = 0;
1735  /* Show decimal if value is below 1ms */
1736  if (exec_time_us < 1000) {
1737  precision = 2;
1738  }
1739  else if (exec_time_us < 10000) {
1740  precision = 1;
1741  }
1742 
1743  std::stringstream stream;
1744  stream << std::fixed << std::setprecision(precision) << (exec_time_us / 1000.0f);
1745  return stream.str() + " ms";
1746 }
1747 
1749  std::string text;
1750  int icon;
1751  const char *tooltip = nullptr;
1752 
1754  void *tooltip_fn_arg = nullptr;
1755  void (*tooltip_fn_free_arg)(void *) = nullptr;
1756 };
1757 
1760 };
1761 
1762 static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
1763 {
1764  NamedAttributeTooltipArg &arg = *static_cast<NamedAttributeTooltipArg *>(argN);
1765 
1766  std::stringstream ss;
1767  ss << TIP_("Accessed named attributes:\n");
1768 
1769  struct NameWithUsage {
1770  StringRefNull name;
1771  eNamedAttrUsage usage;
1772  };
1773 
1774  Vector<NameWithUsage> sorted_used_attribute;
1775  for (auto &&item : arg.usage_by_attribute.items()) {
1776  sorted_used_attribute.append({item.key, item.value});
1777  }
1778  std::sort(sorted_used_attribute.begin(),
1779  sorted_used_attribute.end(),
1780  [](const NameWithUsage &a, const NameWithUsage &b) {
1781  return BLI_strcasecmp_natural(a.name.c_str(), b.name.c_str()) <= 0;
1782  });
1783 
1784  for (const NameWithUsage &attribute : sorted_used_attribute) {
1785  const StringRefNull name = attribute.name;
1786  const eNamedAttrUsage usage = attribute.usage;
1787  ss << " \u2022 \"" << name << "\": ";
1788  Vector<std::string> usages;
1789  if ((usage & eNamedAttrUsage::Read) != eNamedAttrUsage::None) {
1790  usages.append(TIP_("read"));
1791  }
1792  if ((usage & eNamedAttrUsage::Write) != eNamedAttrUsage::None) {
1793  usages.append(TIP_("write"));
1794  }
1795  if ((usage & eNamedAttrUsage::Remove) != eNamedAttrUsage::None) {
1796  usages.append(TIP_("remove"));
1797  }
1798  for (const int i : usages.index_range()) {
1799  ss << usages[i];
1800  if (i < usages.size() - 1) {
1801  ss << ", ";
1802  }
1803  }
1804  ss << "\n";
1805  }
1806  ss << "\n";
1807  ss << TIP_(
1808  "Attributes with these names used within the group may conflict with existing attributes");
1809  return BLI_strdup(ss.str().c_str());
1810 }
1811 
1813  const Map<std::string, eNamedAttrUsage> &usage_by_attribute_name)
1814 {
1815  const int attributes_num = usage_by_attribute_name.size();
1816 
1817  NodeExtraInfoRow row;
1818  row.text = std::to_string(attributes_num) +
1819  TIP_(attributes_num == 1 ? " Named Attribute" : " Named Attributes");
1820  row.icon = ICON_SPREADSHEET;
1822  row.tooltip_fn_arg = new NamedAttributeTooltipArg{usage_by_attribute_name};
1823  row.tooltip_fn_free_arg = [](void *arg) { delete static_cast<NamedAttributeTooltipArg *>(arg); };
1824  return row;
1825 }
1826 
1827 static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const SpaceNode &snode,
1828  const bNode &node)
1829 {
1830  if (node.type == NODE_GROUP) {
1832  snode);
1833  if (root_tree_log == nullptr) {
1834  return std::nullopt;
1835  }
1836  const geo_log::TreeLog *tree_log = root_tree_log->lookup_child_log(node.name);
1837  if (tree_log == nullptr) {
1838  return std::nullopt;
1839  }
1840 
1841  Map<std::string, eNamedAttrUsage> usage_by_attribute;
1842  tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
1843  for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) {
1844  usage_by_attribute.lookup_or_add_as(used_attribute.name,
1845  used_attribute.usage) |= used_attribute.usage;
1846  }
1847  });
1848  if (usage_by_attribute.is_empty()) {
1849  return std::nullopt;
1850  }
1851 
1852  return row_from_used_named_attribute(usage_by_attribute);
1853  }
1854  if (ELEM(node.type,
1858  /* Only show the overlay when the name is passed in from somewhere else. */
1859  LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
1860  if (STREQ(socket->name, "Name")) {
1861  if ((socket->flag & SOCK_IN_USE) == 0) {
1862  return std::nullopt;
1863  }
1864  }
1865  }
1867  snode, node.name);
1868  if (node_log == nullptr) {
1869  return std::nullopt;
1870  }
1871  Map<std::string, eNamedAttrUsage> usage_by_attribute;
1872  for (const geo_log::UsedNamedAttribute &used_attribute : node_log->used_named_attributes()) {
1873  usage_by_attribute.lookup_or_add_as(used_attribute.name,
1874  used_attribute.usage) |= used_attribute.usage;
1875  }
1876  if (usage_by_attribute.is_empty()) {
1877  return std::nullopt;
1878  }
1879  return row_from_used_named_attribute(usage_by_attribute);
1880  }
1881 
1882  return std::nullopt;
1883 }
1884 
1886 {
1888  if (!(snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS)) {
1889  return rows;
1890  }
1891 
1893  snode.edittree->type == NTREE_GEOMETRY) {
1894  if (std::optional<NodeExtraInfoRow> row = node_get_accessed_attributes_row(snode, node)) {
1895  rows.append(std::move(*row));
1896  }
1897  }
1898 
1899  if (snode.overlay.flag & SN_OVERLAY_SHOW_TIMINGS && snode.edittree->type == NTREE_GEOMETRY &&
1902  NodeExtraInfoRow row;
1903  row.text = node_get_execution_time_label(snode, node);
1904  if (!row.text.empty()) {
1905  row.tooltip = TIP_(
1906  "The execution time from the node tree's latest evaluation. For frame and group nodes, "
1907  "the time for all sub-nodes");
1908  row.icon = ICON_PREVIEW_RANGE;
1909  rows.append(std::move(row));
1910  }
1911  }
1913  node);
1914  if (node_log != nullptr) {
1915  for (const std::string &message : node_log->debug_messages()) {
1916  NodeExtraInfoRow row;
1917  row.text = message;
1918  row.icon = ICON_INFO;
1919  rows.append(std::move(row));
1920  }
1921  }
1922 
1923  return rows;
1924 }
1925 
1927  uiBlock &block,
1928  const rctf &rect,
1929  const int row,
1930  const NodeExtraInfoRow &extra_info_row)
1931 {
1932  const float but_icon_left = rect.xmin + 6.0f * U.dpi_fac;
1933  const float but_icon_width = NODE_HEADER_ICON_SIZE * 0.8f;
1934  const float but_icon_right = but_icon_left + but_icon_width;
1935 
1937  uiBut *but_icon = uiDefIconBut(&block,
1938  UI_BTYPE_BUT,
1939  0,
1940  extra_info_row.icon,
1941  (int)but_icon_left,
1942  (int)(rect.ymin + row * (20.0f * U.dpi_fac)),
1943  but_icon_width,
1944  UI_UNIT_Y,
1945  nullptr,
1946  0,
1947  0,
1948  0,
1949  0,
1950  extra_info_row.tooltip);
1951  if (extra_info_row.tooltip_fn != nullptr) {
1952  UI_but_func_tooltip_set(but_icon,
1953  extra_info_row.tooltip_fn,
1954  extra_info_row.tooltip_fn_arg,
1955  extra_info_row.tooltip_fn_free_arg);
1956  }
1957  UI_block_emboss_set(&block, UI_EMBOSS);
1958 
1959  const float but_text_left = but_icon_right + 6.0f * U.dpi_fac;
1960  const float but_text_right = rect.xmax;
1961  const float but_text_width = but_text_right - but_text_left;
1962 
1963  uiBut *but_text = uiDefBut(&block,
1965  0,
1966  extra_info_row.text.c_str(),
1967  (int)but_text_left,
1968  (int)(rect.ymin + row * (20.0f * U.dpi_fac)),
1969  (short)but_text_width,
1970  (short)NODE_DY,
1971  nullptr,
1972  0,
1973  0,
1974  0,
1975  0,
1976  "");
1977 
1978  if (node.flag & NODE_MUTED) {
1981  }
1982 }
1983 
1984 static void node_draw_extra_info_panel(const SpaceNode &snode, const bNode &node, uiBlock &block)
1985 {
1986  Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(snode, node);
1987 
1988  if (extra_info_rows.size() == 0) {
1989  return;
1990  }
1991 
1992  const rctf &rct = node.totr;
1993  float color[4];
1994  rctf extra_info_rect;
1995 
1996  const float width = (node.width - 6.0f) * U.dpi_fac;
1997 
1998  if (node.type == NODE_FRAME) {
1999  extra_info_rect.xmin = rct.xmin;
2000  extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac;
2001  extra_info_rect.ymin = rct.ymin + 2.0f * U.dpi_fac;
2002  extra_info_rect.ymax = rct.ymin + 2.0f * U.dpi_fac;
2003  }
2004  else {
2005  extra_info_rect.xmin = rct.xmin + 3.0f * U.dpi_fac;
2006  extra_info_rect.xmax = rct.xmin + width;
2007  extra_info_rect.ymin = rct.ymax;
2008  extra_info_rect.ymax = rct.ymax + extra_info_rows.size() * (20.0f * U.dpi_fac);
2009 
2010  if (node.flag & NODE_MUTED) {
2012  }
2013  else {
2015  }
2016  color[3] -= 0.35f;
2019  ((rct.xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL));
2020  UI_draw_roundbox_4fv(&extra_info_rect, true, BASIS_RAD, color);
2021 
2022  /* Draw outline. */
2023  const float outline_width = 1.0f;
2024  extra_info_rect.xmin = rct.xmin + 3.0f * U.dpi_fac - outline_width;
2025  extra_info_rect.xmax = rct.xmin + width + outline_width;
2026  extra_info_rect.ymin = rct.ymax - outline_width;
2027  extra_info_rect.ymax = rct.ymax + outline_width + extra_info_rows.size() * (20.0f * U.dpi_fac);
2028 
2032  ((rct.xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL));
2033  UI_draw_roundbox_4fv(&extra_info_rect, false, BASIS_RAD, color);
2034  }
2035 
2036  for (int row : extra_info_rows.index_range()) {
2037  node_draw_extra_info_row(node, block, extra_info_rect, row, extra_info_rows[row]);
2038  }
2039 }
2040 
2041 static void node_draw_basis(const bContext &C,
2042  const View2D &v2d,
2043  const SpaceNode &snode,
2044  bNodeTree &ntree,
2045  bNode &node,
2046  uiBlock &block,
2047  bNodeInstanceKey key)
2048 {
2049  const float iconbutw = NODE_HEADER_ICON_SIZE;
2050 
2051  /* Skip if out of view. */
2052  if (BLI_rctf_isect(&node.totr, &v2d.cur, nullptr) == false) {
2053  UI_block_end(&C, &block);
2054  return;
2055  }
2056 
2057  /* Shadow. */
2058  node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
2059 
2060  const rctf &rct = node.totr;
2061  float color[4];
2062  int color_id = node_get_colorid(node);
2063 
2064  GPU_line_width(1.0f);
2065 
2066  node_draw_extra_info_panel(snode, node, block);
2067 
2068  /* Header. */
2069  {
2070  const rctf rect = {
2071  rct.xmin,
2072  rct.xmax,
2073  rct.ymax - NODE_DY,
2074  rct.ymax,
2075  };
2076 
2077  float color_header[4];
2078 
2079  /* Muted nodes get a mix of the background with the node color. */
2080  if (node.flag & NODE_MUTED) {
2081  UI_GetThemeColorBlend4f(TH_BACK, color_id, 0.1f, color_header);
2082  }
2083  else {
2084  UI_GetThemeColorBlend4f(TH_NODE, color_id, 0.4f, color_header);
2085  }
2086 
2088  UI_draw_roundbox_4fv(&rect, true, BASIS_RAD, color_header);
2089  }
2090 
2091  /* Show/hide icons. */
2092  float iconofs = rct.xmax - 0.35f * U.widget_unit;
2093 
2094  /* Preview. */
2095  if (node.typeinfo->flag & NODE_PREVIEW) {
2096  iconofs -= iconbutw;
2098  uiBut *but = uiDefIconBut(&block,
2100  0,
2101  ICON_MATERIAL,
2102  iconofs,
2103  rct.ymax - NODE_DY,
2104  iconbutw,
2105  UI_UNIT_Y,
2106  nullptr,
2107  0,
2108  0,
2109  0,
2110  0,
2111  "");
2112  UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_preview_toggle");
2113  /* XXX this does not work when node is activated and the operator called right afterwards,
2114  * since active ID is not updated yet (needs to process the notifier).
2115  * This can only work as visual indicator! */
2116  // if (!(node.flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
2117  // UI_but_flag_enable(but, UI_BUT_DISABLED);
2118  UI_block_emboss_set(&block, UI_EMBOSS);
2119  }
2120  /* Group edit. */
2121  if (node.type == NODE_GROUP) {
2122  iconofs -= iconbutw;
2124  uiBut *but = uiDefIconBut(&block,
2126  0,
2127  ICON_NODETREE,
2128  iconofs,
2129  rct.ymax - NODE_DY,
2130  iconbutw,
2131  UI_UNIT_Y,
2132  nullptr,
2133  0,
2134  0,
2135  0,
2136  0,
2137  "");
2138  UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_group_edit");
2139  UI_block_emboss_set(&block, UI_EMBOSS);
2140  }
2141  if (node.type == NODE_CUSTOM && node.typeinfo->ui_icon != ICON_NONE) {
2142  iconofs -= iconbutw;
2144  uiDefIconBut(&block,
2145  UI_BTYPE_BUT,
2146  0,
2147  node.typeinfo->ui_icon,
2148  iconofs,
2149  rct.ymax - NODE_DY,
2150  iconbutw,
2151  UI_UNIT_Y,
2152  nullptr,
2153  0,
2154  0,
2155  0,
2156  0,
2157  "");
2158  UI_block_emboss_set(&block, UI_EMBOSS);
2159  }
2160 
2161  node_add_error_message_button(C, node, block, rct, iconofs);
2162 
2163  /* Title. */
2164  if (node.flag & SELECT) {
2166  }
2167  else {
2168  UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
2169  }
2170 
2171  /* Collapse/expand icon. */
2172  {
2173  const int but_size = U.widget_unit * 0.8f;
2175 
2176  uiBut *but = uiDefIconBut(&block,
2178  0,
2179  ICON_DOWNARROW_HLT,
2180  rct.xmin + (NODE_MARGIN_X / 3),
2181  rct.ymax - NODE_DY / 2.2f - but_size / 2,
2182  but_size,
2183  but_size,
2184  nullptr,
2185  0.0f,
2186  0.0f,
2187  0.0f,
2188  0.0f,
2189  "");
2190 
2191  UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_hide_toggle");
2192  UI_block_emboss_set(&block, UI_EMBOSS);
2193  }
2194 
2195  char showname[128];
2196  nodeLabel(&ntree, &node, showname, sizeof(showname));
2197 
2198  uiBut *but = uiDefBut(&block,
2200  0,
2201  showname,
2202  (int)(rct.xmin + NODE_MARGIN_X + 0.4f),
2203  (int)(rct.ymax - NODE_DY),
2204  (short)(iconofs - rct.xmin - (18.0f * U.dpi_fac)),
2205  (short)NODE_DY,
2206  nullptr,
2207  0,
2208  0,
2209  0,
2210  0,
2211  "");
2212  if (node.flag & NODE_MUTED) {
2214  }
2215 
2216  /* Wire across the node when muted/disabled. */
2217  if (node.flag & NODE_MUTED) {
2218  node_draw_mute_line(C, v2d, snode, node);
2219  }
2220 
2221  /* Body. */
2222  const float outline_width = 1.0f;
2223  {
2224  /* Use warning color to indicate undefined types. */
2225  if (nodeTypeUndefined(&node)) {
2227  }
2228  /* Muted nodes get a mix of the background with the node color. */
2229  else if (node.flag & NODE_MUTED) {
2231  }
2232  else if (node.flag & NODE_CUSTOM_COLOR) {
2233  rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], 1.0f);
2234  }
2235  else {
2237  }
2238 
2239  /* Draw selected nodes fully opaque. */
2240  if (node.flag & SELECT) {
2241  color[3] = 1.0f;
2242  }
2243 
2244  /* Draw muted nodes slightly transparent so the wires inside are visible. */
2245  if (node.flag & NODE_MUTED) {
2246  color[3] -= 0.2f;
2247  }
2248 
2249  const rctf rect = {
2250  rct.xmin,
2251  rct.xmax,
2252  rct.ymin,
2253  rct.ymax - (NODE_DY + outline_width),
2254  };
2255 
2257  UI_draw_roundbox_4fv(&rect, true, BASIS_RAD, color);
2258  }
2259 
2260  /* Header underline. */
2261  {
2262  float color_underline[4];
2263 
2264  if (node.flag & NODE_MUTED) {
2265  UI_GetThemeColor4fv(TH_WIRE, color_underline);
2266  }
2267  else {
2268  UI_GetThemeColorBlend4f(TH_BACK, color_id, 0.2f, color_underline);
2269  }
2270 
2271  const rctf rect = {
2272  rct.xmin,
2273  rct.xmax,
2274  rct.ymax - (NODE_DY + outline_width),
2275  rct.ymax - NODE_DY,
2276  };
2277 
2279  UI_draw_roundbox_4fv(&rect, true, 0.0f, color_underline);
2280  }
2281 
2282  /* Outline. */
2283  {
2284  const rctf rect = {
2285  rct.xmin - outline_width,
2286  rct.xmax + outline_width,
2287  rct.ymin - outline_width,
2288  rct.ymax + outline_width,
2289  };
2290 
2291  /* Color the outline according to active, selected, or undefined status. */
2292  float color_outline[4];
2293 
2294  if (node.flag & SELECT) {
2295  UI_GetThemeColor4fv((node.flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
2296  }
2297  else if (nodeTypeUndefined(&node)) {
2298  UI_GetThemeColor4fv(TH_REDALERT, color_outline);
2299  }
2300  else {
2301  UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color_outline);
2302  }
2303 
2305  UI_draw_roundbox_4fv(&rect, false, BASIS_RAD + outline_width, color_outline);
2306  }
2307 
2308  float scale;
2309  UI_view2d_scale_get(&v2d, &scale, nullptr);
2310 
2311  /* Skip slow socket drawing if zoom is small. */
2312  if (scale > 0.2f) {
2313  node_draw_sockets(v2d, C, ntree, node, block, true, false);
2314  }
2315 
2316  /* Preview. */
2317  bNodeInstanceHash *previews =
2318  (bNodeInstanceHash *)CTX_data_pointer_get(&C, "node_previews").data;
2319  if (node.flag & NODE_PREVIEW && previews) {
2321  if (preview && (preview->xsize && preview->ysize)) {
2322  if (preview->rect && !BLI_rctf_is_empty(&node.prvr)) {
2323  node_draw_preview(preview, &node.prvr);
2324  }
2325  }
2326  }
2327 
2328  UI_block_end(&C, &block);
2329  UI_block_draw(&C, &block);
2330 }
2331 
2332 static void node_draw_hidden(const bContext &C,
2333  const View2D &v2d,
2334  const SpaceNode &snode,
2335  bNodeTree &ntree,
2336  bNode &node,
2337  uiBlock &block)
2338 {
2339  const rctf &rct = node.totr;
2340  float centy = BLI_rctf_cent_y(&rct);
2341  float hiddenrad = BLI_rctf_size_y(&rct) / 2.0f;
2342 
2343  float scale;
2344  UI_view2d_scale_get(&v2d, &scale, nullptr);
2345 
2346  const int color_id = node_get_colorid(node);
2347 
2348  node_draw_extra_info_panel(snode, node, block);
2349 
2350  /* Shadow. */
2351  node_draw_shadow(snode, node, hiddenrad, 1.0f);
2352 
2353  /* Wire across the node when muted/disabled. */
2354  if (node.flag & NODE_MUTED) {
2355  node_draw_mute_line(C, v2d, snode, node);
2356  }
2357 
2358  /* Body. */
2359  float color[4];
2360  {
2361  if (nodeTypeUndefined(&node)) {
2362  /* Use warning color to indicate undefined types. */
2364  }
2365  else if (node.flag & NODE_MUTED) {
2366  /* Muted nodes get a mix of the background with the node color. */
2367  UI_GetThemeColorBlendShade4fv(TH_BACK, color_id, 0.1f, 0, color);
2368  }
2369  else if (node.flag & NODE_CUSTOM_COLOR) {
2370  rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], 1.0f);
2371  }
2372  else {
2373  UI_GetThemeColorBlend4f(TH_NODE, color_id, 0.4f, color);
2374  }
2375 
2376  /* Draw selected nodes fully opaque. */
2377  if (node.flag & SELECT) {
2378  color[3] = 1.0f;
2379  }
2380 
2381  /* Draw muted nodes slightly transparent so the wires inside are visible. */
2382  if (node.flag & NODE_MUTED) {
2383  color[3] -= 0.2f;
2384  }
2385 
2386  UI_draw_roundbox_4fv(&rct, true, hiddenrad, color);
2387  }
2388 
2389  /* Title. */
2390  if (node.flag & SELECT) {
2392  }
2393  else {
2394  UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
2395  }
2396 
2397  /* Collapse/expand icon. */
2398  {
2399  const int but_size = U.widget_unit * 1.0f;
2401 
2402  uiBut *but = uiDefIconBut(&block,
2404  0,
2405  ICON_RIGHTARROW,
2406  rct.xmin + (NODE_MARGIN_X / 3),
2407  centy - but_size / 2,
2408  but_size,
2409  but_size,
2410  nullptr,
2411  0.0f,
2412  0.0f,
2413  0.0f,
2414  0.0f,
2415  "");
2416 
2417  UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_hide_toggle");
2418  UI_block_emboss_set(&block, UI_EMBOSS);
2419  }
2420 
2421  char showname[128];
2422  nodeLabel(&ntree, &node, showname, sizeof(showname));
2423 
2424  uiBut *but = uiDefBut(&block,
2426  0,
2427  showname,
2429  round_fl_to_int(centy - NODE_DY * 0.5f),
2430  (short)(BLI_rctf_size_x(&rct) - ((18.0f + 12.0f) * U.dpi_fac)),
2431  (short)NODE_DY,
2432  nullptr,
2433  0,
2434  0,
2435  0,
2436  0,
2437  "");
2438 
2439  /* Outline. */
2440  {
2441  const float outline_width = 1.0f;
2442  const rctf rect = {
2443  rct.xmin - outline_width,
2444  rct.xmax + outline_width,
2445  rct.ymin - outline_width,
2446  rct.ymax + outline_width,
2447  };
2448 
2449  /* Color the outline according to active, selected, or undefined status. */
2450  float color_outline[4];
2451 
2452  if (node.flag & SELECT) {
2453  UI_GetThemeColor4fv((node.flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
2454  }
2455  else if (nodeTypeUndefined(&node)) {
2456  UI_GetThemeColor4fv(TH_REDALERT, color_outline);
2457  }
2458  else {
2459  UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color_outline);
2460  }
2461 
2463  UI_draw_roundbox_4fv(&rect, false, hiddenrad, color_outline);
2464  }
2465 
2466  if (node.flag & NODE_MUTED) {
2468  }
2469 
2470  /* Scale widget thing. */
2474 
2476  float dx = 0.5f * U.widget_unit;
2477  const float dx2 = 0.15f * U.widget_unit * snode.runtime->aspect;
2478  const float dy = 0.2f * U.widget_unit;
2479 
2481  immVertex2f(pos, rct.xmax - dx, centy - dy);
2482  immVertex2f(pos, rct.xmax - dx, centy + dy);
2483 
2484  immVertex2f(pos, rct.xmax - dx - dx2, centy - dy);
2485  immVertex2f(pos, rct.xmax - dx - dx2, centy + dy);
2486  immEnd();
2487 
2489  dx -= snode.runtime->aspect;
2490 
2492  immVertex2f(pos, rct.xmax - dx, centy - dy);
2493  immVertex2f(pos, rct.xmax - dx, centy + dy);
2494 
2495  immVertex2f(pos, rct.xmax - dx - dx2, centy - dy);
2496  immVertex2f(pos, rct.xmax - dx - dx2, centy + dy);
2497  immEnd();
2498 
2499  immUnbindProgram();
2501 
2502  node_draw_sockets(v2d, C, ntree, node, block, true, false);
2503 
2504  UI_block_end(&C, &block);
2505  UI_block_draw(&C, &block);
2506 }
2507 
2509 {
2510  if (directions == 0) {
2511  return WM_CURSOR_DEFAULT;
2512  }
2513  if ((directions & ~(NODE_RESIZE_TOP | NODE_RESIZE_BOTTOM)) == 0) {
2514  return WM_CURSOR_Y_MOVE;
2515  }
2516  if ((directions & ~(NODE_RESIZE_RIGHT | NODE_RESIZE_LEFT)) == 0) {
2517  return WM_CURSOR_X_MOVE;
2518  }
2519  return WM_CURSOR_EDIT;
2520 }
2521 
2522 void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor)
2523 {
2524  const bNodeTree *ntree = snode.edittree;
2525  if (ntree == nullptr) {
2527  return;
2528  }
2529 
2530  bNode *node;
2531  bNodeSocket *sock;
2532  int wmcursor = WM_CURSOR_DEFAULT;
2533 
2535  snode, &node, &sock, cursor, (eNodeSocketInOut)(SOCK_IN | SOCK_OUT))) {
2537  return;
2538  }
2539 
2540  /* Check nodes front to back. */
2541  for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
2542  if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) {
2543  break; /* First hit on node stops. */
2544  }
2545  }
2546  if (node) {
2547  NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
2548  wmcursor = node_get_resize_cursor(dir);
2549  /* We want to indicate that Frame nodes can be moved/selected on their borders. */
2550  if (node->type == NODE_FRAME && dir == NODE_RESIZE_NONE) {
2551  const rctf frame_inside = node_frame_rect_inside(*node);
2552  if (!BLI_rctf_isect_pt(&frame_inside, cursor[0], cursor[1])) {
2553  wmcursor = WM_CURSOR_NSEW_SCROLL;
2554  }
2555  }
2556  }
2557 
2558  WM_cursor_set(&win, wmcursor);
2559 }
2560 
2562 {
2563  Map<bNodeSocket *, int> counts;
2564  LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
2565  if (link->tosock->flag & SOCK_MULTI_INPUT) {
2566  int &count = counts.lookup_or_add(link->tosock, 0);
2567  count++;
2568  }
2569  }
2570  /* Count temporary links going into this socket. */
2571  if (snode.runtime->linkdrag) {
2572  for (const bNodeLink *link : snode.runtime->linkdrag->links) {
2573  if (link->tosock && (link->tosock->flag & SOCK_MULTI_INPUT)) {
2574  int &count = counts.lookup_or_add(link->tosock, 0);
2575  count++;
2576  }
2577  }
2578  }
2579 
2581  LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
2582  if (socket->flag & SOCK_MULTI_INPUT) {
2583  socket->total_inputs = counts.lookup_default(socket, 0);
2584  }
2585  }
2586  }
2587 }
2588 
2589 /* XXX Does a bounding box update by iterating over all children.
2590  * Not ideal to do this in every draw call, but doing as transform callback doesn't work,
2591  * since the child node totr rects are not updated properly at that point. */
2593 {
2594  const float margin = 1.5f * U.widget_unit;
2595  NodeFrame *data = (NodeFrame *)node.storage;
2596 
2597  /* init rect from current frame size */
2598  rctf rect;
2599  node_to_updated_rect(node, rect);
2600 
2601  /* frame can be resized manually only if shrinking is disabled or no children are attached */
2602  data->flag |= NODE_FRAME_RESIZEABLE;
2603  /* for shrinking bbox, initialize the rect from first child node */
2604  bool bbinit = (data->flag & NODE_FRAME_SHRINK);
2605  /* fit bounding box to all children */
2606  for (const bNode *tnode : nodes) {
2607  if (tnode->parent != &node) {
2608  continue;
2609  }
2610 
2611  /* add margin to node rect */
2612  rctf noderect = tnode->totr;
2613  noderect.xmin -= margin;
2614  noderect.xmax += margin;
2615  noderect.ymin -= margin;
2616  noderect.ymax += margin;
2617 
2618  /* first child initializes frame */
2619  if (bbinit) {
2620  bbinit = false;
2621  rect = noderect;
2622  data->flag &= ~NODE_FRAME_RESIZEABLE;
2623  }
2624  else {
2625  BLI_rctf_union(&rect, &noderect);
2626  }
2627  }
2628 
2629  /* now adjust the frame size from view-space bounding box */
2630  const float2 offset = node_from_view(node, {rect.xmin, rect.ymax});
2631  node.offsetx = offset.x;
2632  node.offsety = offset.y;
2633  const float2 max = node_from_view(node, {rect.xmax, rect.ymin});
2634  node.width = max.x - node.offsetx;
2635  node.height = -max.y + node.offsety;
2636 
2637  node.totr = rect;
2638 }
2639 
2641 {
2642  /* get "global" coords */
2643  const float2 loc = node_to_view(node, float2(0));
2644 
2645  /* reroute node has exactly one input and one output, both in the same place */
2646  bNodeSocket *nsock = (bNodeSocket *)node.outputs.first;
2647  nsock->locx = loc.x;
2648  nsock->locy = loc.y;
2649 
2650  nsock = (bNodeSocket *)node.inputs.first;
2651  nsock->locx = loc.x;
2652  nsock->locy = loc.y;
2653 
2654  const float size = 8.0f;
2655  node.width = size * 2;
2656  node.totr.xmin = loc.x - size;
2657  node.totr.xmax = loc.x + size;
2658  node.totr.ymax = loc.y + size;
2659  node.totr.ymin = loc.y - size;
2660 }
2661 
2662 static void node_update_nodetree(const bContext &C,
2663  bNodeTree &ntree,
2664  Span<bNode *> nodes,
2665  Span<uiBlock *> blocks)
2666 {
2667  /* Make sure socket "used" tags are correct, for displaying value buttons. */
2668  SpaceNode *snode = CTX_wm_space_node(&C);
2669 
2671 
2672  /* Update nodes front to back, so children sizes get updated before parents. */
2673  for (const int i : nodes.index_range()) {
2674  bNode &node = *nodes[i];
2675  uiBlock &block = *blocks[i];
2676  if (node.type == NODE_FRAME) {
2677  /* Frame sizes are calculated after all other nodes have calculating their #totr. */
2678  continue;
2679  }
2680 
2681  if (node.type == NODE_REROUTE) {
2683  }
2684  else {
2685  if (node.flag & NODE_HIDDEN) {
2686  node_update_hidden(node, block);
2687  }
2688  else {
2689  node_update_basis(C, ntree, node, block);
2690  }
2691  }
2692  }
2693 
2694  /* Now calculate the size of frame nodes, which can depend on the size of other nodes. */
2695  for (const int i : nodes.index_range()) {
2696  if (nodes[i]->type == NODE_FRAME) {
2697  frame_node_prepare_for_draw(*nodes[i], nodes);
2698  }
2699  }
2700 }
2701 
2703  const bNode &node,
2704  const SpaceNode &snode)
2705 {
2706  const float aspect = snode.runtime->aspect;
2707  /* XXX font id is crap design */
2708  const int fontid = UI_style_get()->widgetlabel.uifont_id;
2709  const NodeFrame *data = (const NodeFrame *)node.storage;
2710  const float font_size = data->label_size / aspect;
2711 
2712  char label[MAX_NAME];
2713  nodeLabel(&ntree, &node, label, sizeof(label));
2714 
2715  BLF_enable(fontid, BLF_ASPECT);
2716  BLF_aspect(fontid, aspect, aspect, 1.0f);
2717  /* clamp otherwise it can suck up a LOT of memory */
2718  BLF_size(fontid, MIN2(24.0f, font_size) * U.pixelsize, U.dpi);
2719 
2720  /* title color */
2721  int color_id = node_get_colorid(node);
2722  uchar color[3];
2723  UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
2724  BLF_color3ubv(fontid, color);
2725 
2726  const float margin = (float)(NODE_DY / 4);
2727  const float width = BLF_width(fontid, label, sizeof(label));
2728  const float ascender = BLF_ascender(fontid);
2729  const int label_height = ((margin / aspect) + (ascender * aspect));
2730 
2731  /* 'x' doesn't need aspect correction */
2732  const rctf &rct = node.totr;
2733  /* XXX a bit hacky, should use separate align values for x and y */
2734  float x = BLI_rctf_cent_x(&rct) - (0.5f * width);
2735  float y = rct.ymax - label_height;
2736 
2737  /* label */
2738  const bool has_label = node.label[0] != '\0';
2739  if (has_label) {
2740  BLF_position(fontid, x, y, 0);
2741  BLF_draw(fontid, label, sizeof(label));
2742  }
2743 
2744  /* draw text body */
2745  if (node.id) {
2746  const Text *text = (const Text *)node.id;
2747  const int line_height_max = BLF_height_max(fontid);
2748  const float line_spacing = (line_height_max * aspect);
2749  const float line_width = (BLI_rctf_size_x(&rct) - margin) / aspect;
2750 
2751  /* 'x' doesn't need aspect correction */
2752  x = rct.xmin + margin;
2753  y = rct.ymax - label_height - (has_label ? line_spacing : 0);
2754 
2755  /* early exit */
2756  int y_min = y + ((margin * 2) - (y - rct.ymin));
2757 
2759  BLF_clipping(fontid,
2760  rct.xmin,
2761  /* round to avoid clipping half-way through a line */
2762  y - (floorf(((y - rct.ymin) - (margin * 2)) / line_spacing) * line_spacing),
2763  rct.xmin + line_width,
2764  rct.ymax);
2765 
2766  BLF_wordwrap(fontid, line_width);
2767 
2768  LISTBASE_FOREACH (const TextLine *, line, &text->lines) {
2769  struct ResultBLF info;
2770  if (line->line[0]) {
2771  BLF_position(fontid, x, y, 0);
2772  BLF_draw_ex(fontid, line->line, line->len, &info);
2773  y -= line_spacing * info.lines;
2774  }
2775  else {
2776  y -= line_spacing;
2777  }
2778  if (y < y_min) {
2779  break;
2780  }
2781  }
2782 
2784  }
2785 
2786  BLF_disable(fontid, BLF_ASPECT);
2787 }
2788 
2789 static void frame_node_draw(const bContext &C,
2790  const ARegion &region,
2791  const SpaceNode &snode,
2792  bNodeTree &ntree,
2793  bNode &node,
2794  uiBlock &block)
2795 {
2796  /* skip if out of view */
2797  if (BLI_rctf_isect(&node.totr, &region.v2d.cur, nullptr) == false) {
2798  UI_block_end(&C, &block);
2799  return;
2800  }
2801 
2802  float color[4];
2804  const float alpha = color[3];
2805 
2806  /* shadow */
2807  node_draw_shadow(snode, node, BASIS_RAD, alpha);
2808 
2809  /* body */
2810  if (node.flag & NODE_CUSTOM_COLOR) {
2811  rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], alpha);
2812  }
2813  else {
2815  }
2816 
2817  const rctf &rct = node.totr;
2819  UI_draw_roundbox_4fv(&rct, true, BASIS_RAD, color);
2820 
2821  /* outline active and selected emphasis */
2822  if (node.flag & SELECT) {
2823  if (node.flag & NODE_ACTIVE) {
2825  }
2826  else {
2828  }
2829 
2830  UI_draw_roundbox_aa(&rct, false, BASIS_RAD, color);
2831  }
2832 
2833  /* label and text */
2834  frame_node_draw_label(ntree, node, snode);
2835 
2836  node_draw_extra_info_panel(snode, node, block);
2837 
2838  UI_block_end(&C, &block);
2839  UI_block_draw(&C, &block);
2840 }
2841 
2842 static void reroute_node_draw(
2843  const bContext &C, ARegion &region, bNodeTree &ntree, bNode &node, uiBlock &block)
2844 {
2845  char showname[128]; /* 128 used below */
2846  const rctf &rct = node.totr;
2847 
2848  /* skip if out of view */
2849  if (rct.xmax < region.v2d.cur.xmin || rct.xmin > region.v2d.cur.xmax ||
2850  rct.ymax < region.v2d.cur.ymin || node.totr.ymin > region.v2d.cur.ymax) {
2851  UI_block_end(&C, &block);
2852  return;
2853  }
2854 
2855  if (node.label[0] != '\0') {
2856  /* draw title (node label) */
2857  BLI_strncpy(showname, node.label, sizeof(showname));
2858  const short width = 512;
2859  const int x = BLI_rctf_cent_x(&node.totr) - (width / 2);
2860  const int y = node.totr.ymax;
2861 
2862  uiBut *label_but = uiDefBut(&block,
2864  0,
2865  showname,
2866  x,
2867  y,
2868  width,
2869  (short)NODE_DY,
2870  nullptr,
2871  0,
2872  0,
2873  0,
2874  0,
2875  nullptr);
2876 
2878  }
2879 
2880  /* only draw input socket. as they all are placed on the same position.
2881  * highlight also if node itself is selected, since we don't display the node body separately!
2882  */
2883  node_draw_sockets(region.v2d, C, ntree, node, block, false, node.flag & SELECT);
2884 
2885  UI_block_end(&C, &block);
2886  UI_block_draw(&C, &block);
2887 }
2888 
2889 static void node_draw(const bContext &C,
2890  ARegion &region,
2891  const SpaceNode &snode,
2892  bNodeTree &ntree,
2893  bNode &node,
2894  uiBlock &block,
2895  bNodeInstanceKey key)
2896 {
2897  if (node.type == NODE_FRAME) {
2898  frame_node_draw(C, region, snode, ntree, node, block);
2899  }
2900  else if (node.type == NODE_REROUTE) {
2901  reroute_node_draw(C, region, ntree, node, block);
2902  }
2903  else {
2904  const View2D &v2d = region.v2d;
2905  if (node.flag & NODE_HIDDEN) {
2906  node_draw_hidden(C, v2d, snode, ntree, node, block);
2907  }
2908  else {
2909  node_draw_basis(C, v2d, snode, ntree, node, block, key);
2910  }
2911  }
2912 }
2913 
2914 #define USE_DRAW_TOT_UPDATE
2915 
2916 static void node_draw_nodetree(const bContext &C,
2917  ARegion &region,
2918  SpaceNode &snode,
2919  bNodeTree &ntree,
2920  Span<bNode *> nodes,
2921  Span<uiBlock *> blocks,
2922  bNodeInstanceKey parent_key)
2923 {
2924 #ifdef USE_DRAW_TOT_UPDATE
2925  BLI_rctf_init_minmax(&region.v2d.tot);
2926 #endif
2927 
2928  /* Draw background nodes, last nodes in front. */
2929  for (const int i : nodes.index_range()) {
2930 #ifdef USE_DRAW_TOT_UPDATE
2931  /* Unrelated to background nodes, update the v2d->tot,
2932  * can be anywhere before we draw the scroll bars. */
2933  BLI_rctf_union(&region.v2d.tot, &nodes[i]->totr);
2934 #endif
2935 
2936  if (!(nodes[i]->flag & NODE_BACKGROUND)) {
2937  continue;
2938  }
2939 
2940  bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
2941  node_draw(C, region, snode, ntree, *nodes[i], *blocks[i], key);
2942  }
2943 
2944  /* Node lines. */
2946  nodelink_batch_start(snode);
2947 
2948  LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
2949  if (!nodeLinkIsHidden(link) && !nodeLinkIsSelected(link)) {
2950  node_draw_link(C, region.v2d, snode, *link, false);
2951  }
2952  }
2953 
2954  /* Draw selected node links after the unselected ones, so they are shown on top. */
2955  LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
2956  if (!nodeLinkIsHidden(link) && nodeLinkIsSelected(link)) {
2957  node_draw_link(C, region.v2d, snode, *link, true);
2958  }
2959  }
2960 
2961  nodelink_batch_end(snode);
2963 
2964  /* Draw foreground nodes, last nodes in front. */
2965  for (const int i : nodes.index_range()) {
2966  if (nodes[i]->flag & NODE_BACKGROUND) {
2967  continue;
2968  }
2969 
2970  bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
2971  node_draw(C, region, snode, ntree, *nodes[i], *blocks[i], key);
2972  }
2973 }
2974 
2975 /* Draw the breadcrumb on the bottom of the editor. */
2976 static void draw_tree_path(const bContext &C, ARegion &region)
2977 {
2978  using namespace blender;
2979 
2981  wmOrtho2_region_pixelspace(&region);
2982 
2983  const rcti *rect = ED_region_visible_rect(&region);
2984 
2985  const uiStyle *style = UI_style_get_dpi();
2986  const float padding_x = 16 * UI_DPI_FAC;
2987  const int x = rect->xmin + padding_x;
2988  const int y = region.winy - UI_UNIT_Y * 0.6f;
2989  const int width = BLI_rcti_size_x(rect) - 2 * padding_x;
2990 
2991  uiBlock *block = UI_block_begin(&C, &region, __func__, UI_EMBOSS_NONE);
2992  uiLayout *layout = UI_block_layout(
2993  block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y, width, 1, 0, style);
2994 
2996  ui::template_breadcrumbs(*layout, context_path);
2997 
2998  UI_block_layout_resolve(block, nullptr, nullptr);
2999  UI_block_end(&C, block);
3000  UI_block_draw(&C, block);
3001 
3003 }
3004 
3005 static void snode_setup_v2d(SpaceNode &snode, ARegion &region, const float2 &center)
3006 {
3007  View2D &v2d = region.v2d;
3008 
3009  /* Shift view to node tree center. */
3010  UI_view2d_center_set(&v2d, center[0], center[1]);
3011  UI_view2d_view_ortho(&v2d);
3012 
3013  /* Aspect + font, set each time. */
3014  snode.runtime->aspect = BLI_rctf_size_x(&v2d.cur) / (float)region.winx;
3015  // XXX snode->curfont = uiSetCurFont_ext(snode->aspect);
3016 }
3017 
3018 static void draw_nodetree(const bContext &C,
3019  ARegion &region,
3020  bNodeTree &ntree,
3021  bNodeInstanceKey parent_key)
3022 {
3023  SpaceNode *snode = CTX_wm_space_node(&C);
3024 
3025  Vector<bNode *> nodes = ntree.nodes;
3026 
3027  Array<uiBlock *> blocks = node_uiblocks_init(C, nodes);
3028 
3029  node_update_nodetree(C, ntree, nodes, blocks);
3030  node_draw_nodetree(C, region, *snode, ntree, nodes, blocks, parent_key);
3031 }
3032 
3036 static void draw_background_color(const SpaceNode &snode)
3037 {
3038  const int max_tree_length = 3;
3039  const float bright_factor = 0.25f;
3040 
3041  /* We ignore the first element of the path since it is the top-most tree and it doesn't need to
3042  * be brighter. We also set a cap to how many levels we want to set apart, to avoid the
3043  * background from getting too bright. */
3044  const int clamped_tree_path_length = BLI_listbase_count_at_most(&snode.treepath,
3045  max_tree_length);
3046  const int depth = max_ii(0, clamped_tree_path_length - 1);
3047 
3048  float color[3];
3050  mul_v3_fl(color, 1.0f + bright_factor * depth);
3051  GPU_clear_color(color[0], color[1], color[2], 1.0);
3052 }
3053 
3054 void node_draw_space(const bContext &C, ARegion &region)
3055 {
3056  wmWindow *win = CTX_wm_window(&C);
3057  SpaceNode &snode = *CTX_wm_space_node(&C);
3058  View2D &v2d = region.v2d;
3059 
3060  /* Setup off-screen buffers. */
3061  GPUViewport *viewport = WM_draw_region_get_viewport(&region);
3062 
3063  GPUFrameBuffer *framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(viewport);
3064  GPU_framebuffer_bind_no_srgb(framebuffer_overlay);
3065 
3066  UI_view2d_view_ortho(&v2d);
3067  draw_background_color(snode);
3069  GPU_scissor_test(true);
3070 
3071  /* XXX `snode->runtime->cursor` set in coordinate-space for placing new nodes,
3072  * used for drawing noodles too. */
3073  UI_view2d_region_to_view(&region.v2d,
3074  win->eventstate->xy[0] - region.winrct.xmin,
3075  win->eventstate->xy[1] - region.winrct.ymin,
3076  &snode.runtime->cursor[0],
3077  &snode.runtime->cursor[1]);
3078  snode.runtime->cursor[0] /= UI_DPI_FAC;
3079  snode.runtime->cursor[1] /= UI_DPI_FAC;
3080 
3082 
3083  /* Only set once. */
3085 
3086  /* Nodes. */
3088 
3089  const int grid_levels = UI_GetThemeValueType(TH_NODE_GRID_LEVELS, SPACE_NODE);
3091 
3092  /* Draw parent node trees. */
3093  if (snode.treepath.last) {
3094  bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
3095 
3096  /* Update tree path name (drawn in the bottom left). */
3097  ID *name_id = (path->nodetree && path->nodetree != snode.nodetree) ? &path->nodetree->id :
3098  snode.id;
3099 
3100  if (name_id && UNLIKELY(!STREQ(path->display_name, name_id->name + 2))) {
3101  BLI_strncpy(path->display_name, name_id->name + 2, sizeof(path->display_name));
3102  }
3103 
3104  /* Current View2D center, will be set temporarily for parent node trees. */
3105  float center[2];
3106  UI_view2d_center_get(&v2d, &center[0], &center[1]);
3107 
3108  /* Store new view center in path and current edit tree. */
3109  copy_v2_v2(path->view_center, center);
3110  if (snode.edittree) {
3112  }
3113 
3114  /* Top-level edit tree. */
3115  bNodeTree *ntree = path->nodetree;
3116  if (ntree) {
3117  snode_setup_v2d(snode, region, center);
3118 
3119  /* Backdrop. */
3120  draw_nodespace_back_pix(C, region, snode, path->parent_key);
3121 
3122  {
3123  float original_proj[4][4];
3124  GPU_matrix_projection_get(original_proj);
3125 
3126  GPU_matrix_push();
3128 
3129  wmOrtho2_pixelspace(region.winx, region.winy);
3130 
3132 
3133  GPU_matrix_pop();
3134  GPU_matrix_projection_set(original_proj);
3135  }
3136 
3137  draw_nodetree(C, region, *ntree, path->parent_key);
3138  }
3139 
3140  /* Temporary links. */
3142  GPU_line_smooth(true);
3143  if (snode.runtime->linkdrag) {
3144  for (const bNodeLink *link : snode.runtime->linkdrag->links) {
3145  node_draw_link(C, v2d, snode, *link, true);
3146  }
3147  }
3148  GPU_line_smooth(false);
3150 
3151  if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && snode.flag & SNODE_SHOW_GPENCIL) {
3152  /* Draw grease-pencil annotations. */
3153  ED_annotation_draw_view2d(&C, true);
3154  }
3155  }
3156  else {
3157 
3158  /* Backdrop. */
3160  }
3161 
3163 
3164  /* Reset view matrix. */
3166 
3167  if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS) {
3168  if (snode.flag & SNODE_SHOW_GPENCIL && snode.treepath.last) {
3169  /* Draw grease-pencil (screen strokes, and also paint-buffer). */
3170  ED_annotation_draw_view2d(&C, false);
3171  }
3172 
3173  /* Draw context path. */
3174  if (snode.overlay.flag & SN_OVERLAY_SHOW_PATH && snode.edittree) {
3175  draw_tree_path(C, region);
3176  }
3177  }
3178 
3179  /* Scrollers. */
3180  UI_view2d_scrollers_draw(&v2d, nullptr);
3181 }
3182 
3183 } // namespace blender::ed::space_node
typedef float(TangentPoint)[2]
void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state, float x, float y, int img_w, int img_h, eGPUTextureFormat gpu_format, bool use_filter, void *rect, float xzoom, float yzoom, const float color[4])
Definition: glutil.c:333
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
Definition: glutil.c:44
PointerRNA CTX_data_pointer_get(const bContext *C, const char *member)
Definition: context.c:462
struct SpaceNode * CTX_wm_space_node(const bContext *C)
Definition: context.c:878
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
GeometryComponentType
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
@ GEO_COMPONENT_TYPE_INSTANCES
@ GEO_COMPONENT_TYPE_EDIT
@ GEO_COMPONENT_TYPE_CURVE
@ GEO_COMPONENT_TYPE_VOLUME
const char * BKE_idtype_idcode_to_name(short idcode)
Definition: idtype.c:142
void id_us_ensure_real(struct ID *id)
Definition: lib_id.c:260
void nodeFromView(const struct bNode *node, float x, float y, float *rx, float *ry)
#define NODE_CLASS_OUTPUT
Definition: BKE_node.h:346
struct bNodeTree * ntreeFromID(struct ID *id)
Definition: node.cc:3231
#define NODE_REROUTE
Definition: BKE_node.h:986
#define GEO_NODE_STORE_NAMED_ATTRIBUTE
Definition: BKE_node.h:1497
bool nodeLinkIsHidden(const struct bNodeLink *link)
#define NODE_CLASS_INTERFACE
Definition: BKE_node.h:357
#define NODE_CLASS_MATTE
Definition: BKE_node.h:352
#define NODE_CLASS_CONVERTER
Definition: BKE_node.h:351
#define GEO_NODE_REMOVE_ATTRIBUTE
Definition: BKE_node.h:1499
bool nodeTypeUndefined(const struct bNode *node)
#define NODE_CUSTOM
Definition: BKE_node.h:981
#define NODE_CLASS_PATTERN
Definition: BKE_node.h:354
int nodeSocketIsHidden(const struct bNodeSocket *sock)
#define GEO_NODE_INPUT_NAMED_ATTRIBUTE
Definition: BKE_node.h:1498
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
#define NODE_CLASS_DISTORT
Definition: BKE_node.h:353
#define NODE_CLASS_OP_VECTOR
Definition: BKE_node.h:348
void nodeLabel(const struct bNodeTree *ntree, const struct bNode *node, char *label, int maxlen)
#define NODE_CLASS_LAYOUT
Definition: BKE_node.h:361
bool nodeLinkIsSelected(const struct bNodeLink *link)
#define NODE_CLASS_OP_COLOR
Definition: BKE_node.h:347
#define NODE_CLASS_INPUT
Definition: BKE_node.h:345
#define NODE_CLASS_OP_FILTER
Definition: BKE_node.h:349
const bNodeInstanceKey NODE_INSTANCE_KEY_NONE
Definition: node.cc:3897
#define NODE_FRAME
Definition: BKE_node.h:985
#define NODE_CLASS_GROUP
Definition: BKE_node.h:350
#define NODE_CLASS_ATTRIBUTE
Definition: BKE_node.h:360
#define NODE_CLASS_TEXTURE
Definition: BKE_node.h:355
void nodeToView(const struct bNode *node, float x, float y, float *rx, float *ry)
#define NODE_CLASS_SHADER
Definition: BKE_node.h:358
void * BKE_node_instance_hash_lookup(bNodeInstanceHash *hash, bNodeInstanceKey key)
Definition: node.cc:3965
const char * nodeSocketLabel(const struct bNodeSocket *sock)
bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, const struct bNodeTree *ntree, const struct bNode *node)
#define NODE_CLASS_SCRIPT
Definition: BKE_node.h:356
General operations, lookup, etc. for blender objects.
@ BLF_WORD_WRAP
Definition: BLF_api.h:340
@ BLF_ASPECT
Definition: BLF_api.h:339
@ BLF_CLIPPING
Definition: BLF_api.h:335
void BLF_aspect(int fontid, float x, float y, float z)
Definition: blf.c:288
void BLF_color3ubv(int fontid, const unsigned char rgb[3])
Definition: blf.c:407
void BLF_clipping(int fontid, int xmin, int ymin, int xmax, int ymax)
Definition: blf.c:775
void BLF_disable(int fontid, int option)
Definition: blf.c:279
void BLF_draw_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info) ATTR_NONNULL(2)
Definition: blf.c:521
float BLF_width(int fontid, const char *str, size_t str_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: blf.c:688
void BLF_draw(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2)
Definition: blf.c:538
void BLF_enable(int fontid, int option)
Definition: blf.c:270
int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT
Definition: blf.c:722
void BLF_size(int fontid, float size, int dpi)
Definition: blf.c:363
int BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT
Definition: blf.c:755
void BLF_wordwrap(int fontid, int wrap_width)
Definition: blf.c:787
void BLF_position(int fontid, float x, float y, float z)
Definition: blf.c:308
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
int BLI_listbase_count_at_most(const struct ListBase *listbase, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:340
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
#define M_PI
Definition: BLI_math_base.h:20
MINLINE void rgba_float_args_set(float col[4], float r, float g, float b, float a)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
bool BLI_rctf_is_empty(const struct rctf *rect)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition: BLI_rect.h:190
void BLI_rctf_union(struct rctf *rct_a, const struct rctf *rct_b)
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition: BLI_rect.h:181
bool BLI_rctf_isect(const struct rctf *src1, const struct rctf *src2, struct rctf *dest)
BLI_INLINE float BLI_rctf_cent_x(const struct rctf *rct)
Definition: BLI_rect.h:177
void BLI_rcti_resize(struct rcti *rect, int x, int y)
Definition: rct.c:599
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition: BLI_rect.h:186
bool BLI_rctf_isect_pt(const struct rctf *rect, float x, float y)
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition: BLI_rect.h:173
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:198
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition: BLI_rect.h:169
void BLI_rctf_init_minmax(struct rctf *rect)
Definition: rct.c:483
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:33
size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL()
Definition: string.c:1114
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
#define SWAP(type, a, b)
#define UNUSED(x)
#define MAX2(a, b)
#define UNLIKELY(x)
#define ELEM(...)
#define MIN2(a, b)
#define STREQ(a, b)
#define TIP_(msgid)
#define IFACE_(msgid)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_TE
Definition: DNA_ID_enums.h:52
@ ID_IM
Definition: DNA_ID_enums.h:53
@ ID_NT
Definition: DNA_ID_enums.h:68
@ ID_LA
Definition: DNA_ID_enums.h:55
@ ID_WO
Definition: DNA_ID_enums.h:59
@ ID_MA
Definition: DNA_ID_enums.h:51
@ ID_GR
Definition: DNA_ID_enums.h:65
@ ID_OB
Definition: DNA_ID_enums.h:47
#define MAX_NAME
Definition: DNA_defs.h:48
#define NODE_OPTIONS
#define NODE_FRAME_RESIZEABLE
#define NODE_CUSTOM_COLOR
#define NTREE_TEXTURE
#define NODE_BACKGROUND
#define NODE_DO_OUTPUT
#define NTREE_GEOMETRY
#define NODE_MUTED
#define NTREE_COMPOSIT
#define NODE_HIDDEN
eNodeSocketInOut
@ SOCK_OUT
@ SOCK_IN
#define NODE_PREVIEW
@ SOCK_MULTI_INPUT
@ SOCK_IN_USE
#define NODE_FRAME_SHRINK
@ SOCK_DISPLAY_SHAPE_CIRCLE_DOT
@ SOCK_DISPLAY_SHAPE_CIRCLE
@ SOCK_DISPLAY_SHAPE_SQUARE_DOT
@ SOCK_DISPLAY_SHAPE_SQUARE
@ SOCK_DISPLAY_SHAPE_DIAMOND
@ SOCK_DISPLAY_SHAPE_DIAMOND_DOT
@ SOCK_CUSTOM
#define NODE_SELECT
#define NTREE_SHADER
#define NODE_ACTIVE
@ SN_OVERLAY_SHOW_PATH
@ SN_OVERLAY_SHOW_TIMINGS
@ SN_OVERLAY_SHOW_OVERLAYS
@ SN_OVERLAY_SHOW_NAMED_ATTRIBUTES
@ SNODE_SHOW_GPENCIL
@ SPACE_NODE
#define NODE_GRID_STEP_SIZE
Definition: ED_node.h:36
const rcti * ED_region_visible_rect(ARegion *region)
Definition: area.c:3763
#define REGION_DRAW_POST_VIEW
Definition: ED_space_api.h:62
void ED_region_draw_cb_draw(const struct bContext *C, struct ARegion *region, int type)
#define REGION_DRAW_PRE_VIEW
Definition: ED_space_api.h:64
NSNotificationCenter * center
struct GPUFrameBuffer GPUFrameBuffer
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *fb)
void immUniform4f(const char *name, float x, float y, float z, float w)
void immAttr4fv(uint attr_id, const float data[4])
void immUniform2f(const char *name, float x, float y)
void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
void immUnbindProgram(void)
void immVertex2f(uint attr_id, float x, float y)
void immAttr1f(uint attr_id, float x)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniform1i(const char *name, int x)
void immBeginAtMost(GPUPrimType, uint max_vertex_len)
void immAttr1u(uint attr_id, uint x)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat(void)
void immBegin(GPUPrimType, uint vertex_len)
void immEnd(void)
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
void immRectf(uint pos, float x1, float y1, float x2, float y2)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
void GPU_matrix_pop(void)
Definition: gpu_matrix.cc:126
void GPU_matrix_pop_projection(void)
Definition: gpu_matrix.cc:140
void GPU_matrix_push(void)
Definition: gpu_matrix.cc:119
#define GPU_matrix_projection_get(x)
Definition: GPU_matrix.h:228
#define GPU_matrix_projection_set(x)
Definition: GPU_matrix.h:226
void GPU_matrix_identity_set(void)
Definition: gpu_matrix.cc:168
void GPU_matrix_push_projection(void)
Definition: gpu_matrix.cc:133
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:20
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:19
@ GPU_SHADER_KEYFRAME_SHAPE
Definition: GPU_shader.h:192
@ GPU_SHADER_2D_CHECKER
Definition: GPU_shader.h:221
@ GPU_SHADER_2D_UNIFORM_COLOR
Definition: GPU_shader.h:201
@ GPU_SHADER_2D_IMAGE_COLOR
Definition: GPU_shader.h:217
@ GPU_KEYFRAME_SHAPE_INNER_DOT
Definition: GPU_shader.h:398
@ GPU_KEYFRAME_SHAPE_CIRCLE
Definition: GPU_shader.h:395
@ GPU_KEYFRAME_SHAPE_DIAMOND
Definition: GPU_shader.h:394
#define GPU_KEYFRAME_SHAPE_SQUARE
Definition: GPU_shader.h:403
float float2[2]
void GPU_program_point_size(bool enable)
Definition: gpu_state.cc:172
eGPUBlend
Definition: GPU_state.h:59
@ GPU_BLEND_NONE
Definition: GPU_state.h:60
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:62
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:39
void GPU_scissor_test(bool enable)
Definition: gpu_state.cc:180
void GPU_line_width(float width)
Definition: gpu_state.cc:158
void GPU_line_smooth(bool enable)
Definition: gpu_state.cc:75
eGPUBlend GPU_blend_get(void)
Definition: gpu_state.cc:218
@ GPU_DEPTH_NONE
Definition: GPU_state.h:83
void GPU_depth_test(eGPUDepthTest test)
Definition: gpu_state.cc:65
@ GPU_RGBA8
Definition: GPU_texture.h:87
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_U32
GPUFrameBuffer * GPU_viewport_framebuffer_overlay_get(GPUViewport *viewport)
Definition: gpu_viewport.c:574
Read Guarded memory(de)allocation.
NODE_GROUP_OUTPUT
NODE_GROUP
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
#define C
Definition: RandGen.cpp:25
@ UI_LAYOUT_ALIGN_RIGHT
@ UI_BUT_TEXT_LEFT
Definition: UI_interface.h:259
#define UI_ALPHA_CHECKER_LIGHT
@ UI_LAYOUT_VERTICAL
#define UI_UNIT_Y
void uiLayoutSetActive(uiLayout *layout, bool active)
eUIEmbossType UI_block_emboss_get(uiBlock *block)
Definition: interface.cc:3624
@ UI_BUT_DISABLED
Definition: UI_interface.h:196
@ UI_BUT_INACTIVE
Definition: UI_interface.h:203
eUIEmbossType
Definition: UI_interface.h:107
@ UI_EMBOSS_NONE
Definition: UI_interface.h:109
@ UI_EMBOSS
Definition: UI_interface.h:108
const struct uiStyle * UI_style_get_dpi(void)
uiBut * uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5336
void UI_draw_roundbox_4fv(const struct rctf *rect, bool filled, float rad, const float col[4])
uiBut * uiDefBut(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:4806
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFreeArgFunc free_arg)
Definition: interface.cc:6029
const struct uiStyle * UI_style_get(void)
#define UI_ALPHA_CHECKER_DARK
@ UI_LAYOUT_PANEL
char *(* uiButToolTipFunc)(struct bContext *C, void *argN, const char *tip)
Definition: UI_interface.h:537
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
void UI_draw_roundbox_corner_set(int type)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void UI_block_end(const struct bContext *C, uiBlock *block)
void uiLayoutSetTooltipFunc(uiLayout *layout, uiButToolTipFunc func, void *arg, uiCopyArgFunc copy_arg, uiFreeArgFunc free_arg)
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss)
Definition: interface.cc:3629
void UI_block_draw(const struct bContext *C, struct uiBlock *block)
#define UI_DPI_FAC
Definition: UI_interface.h:305
void UI_but_drawflag_disable(uiBut *but, int flag)
Definition: interface.cc:5878
uiLayout * UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, const struct uiStyle *style)
void UI_but_func_set(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2)
Definition: interface.cc:6000
void UI_draw_roundbox_aa(const struct rctf *rect, bool filled, float rad, const float color[4])
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr)
@ UI_CNR_BOTTOM_LEFT
@ UI_CNR_BOTTOM_RIGHT
@ UI_CNR_ALL
@ UI_CNR_TOP_LEFT
@ UI_CNR_TOP_RIGHT
@ UI_CNR_NONE
uiBlock * UI_block_begin(const struct bContext *C, struct ARegion *region, const char *name, eUIEmbossType emboss)
void UI_draw_roundbox_4fv_ex(const struct rctf *rect, const float inner1[4], const float inner2[4], float shade_dir, const float outline[4], float outline_width, float rad)
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
void UI_block_flag_enable(uiBlock *block, int flag)
Definition: interface.cc:5848
@ UI_BTYPE_BUT
Definition: UI_interface.h:330
@ UI_BTYPE_BUT_TOGGLE
Definition: UI_interface.h:345
@ UI_BTYPE_LABEL
Definition: UI_interface.h:354
void UI_but_flag_enable(uiBut *but, int flag)
Definition: interface.cc:5858
@ UI_BLOCK_CLIP_EVENTS
Definition: UI_interface.h:150
void UI_block_bounds_set_explicit(uiBlock *block, int minx, int miny, int maxx, int maxy)
Definition: interface.cc:630
void UI_block_align_end(uiBlock *block)
Definition: interface.cc:3923
void UI_GetThemeColor3fv(int colorid, float col[3])
Definition: resources.c:1165
int UI_GetThemeValueType(int colorid, int spacetype)
Definition: resources.c:1159
@ TH_NODE_FRAME
Definition: UI_resources.h:174
@ TH_NODE_INPUT
Definition: UI_resources.h:161
@ TH_NODE
Definition: UI_resources.h:160
@ TH_NODE_FILTER
Definition: UI_resources.h:164
@ TH_NODE_GROUP
Definition: UI_resources.h:173
@ TH_GRID
Definition: UI_resources.h:68
@ TH_NODE_SCRIPT
Definition: UI_resources.h:168
@ TH_BACK
Definition: UI_resources.h:39
@ TH_NODE_GEOMETRY
Definition: UI_resources.h:177
@ TH_NODE_OUTPUT
Definition: UI_resources.h:162
@ TH_NODE_COLOR
Definition: UI_resources.h:163
@ TH_WIRE
Definition: UI_resources.h:69
@ TH_NODE_PATTERN
Definition: UI_resources.h:167
@ TH_NODE_ATTRIBUTE
Definition: UI_resources.h:178
@ TH_NODE_DISTORT
Definition: UI_resources.h:176
@ TH_REDALERT
Definition: UI_resources.h:34
@ TH_NODE_MATTE
Definition: UI_resources.h:175
@ TH_NODE_GRID_LEVELS
Definition: UI_resources.h:226
@ TH_NODE_TEXTURE
Definition: UI_resources.h:166
@ TH_NODE_VECTOR
Definition: UI_resources.h:165
@ TH_NODE_CONVERTER
Definition: UI_resources.h:172
@ TH_SELECT
Definition: UI_resources.h:72
@ TH_NODE_LAYOUT
Definition: UI_resources.h:169
@ TH_TEXT
Definition: UI_resources.h:42
@ TH_NODE_SHADER
Definition: UI_resources.h:170
@ TH_WIRE_INNER
Definition: UI_resources.h:70
@ TH_NODE_INTERFACE
Definition: UI_resources.h:171
@ TH_ACTIVE
Definition: UI_resources.h:73
void UI_GetThemeColorBlend4f(int colorid1, int colorid2, float fac, float r_col[4])
Definition: resources.c:1122
void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int offset, float col[4])
Definition: resources.c:1299
void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4])
Definition: resources.c:1259
void UI_GetThemeColor4fv(int colorid, float col[4])
Definition: resources.c:1173
void UI_GetThemeColorBlendShade3ubv(int colorid1, int colorid2, float fac, int offset, unsigned char col[3])
Definition: resources.c:1225
void UI_view2d_center_set(struct View2D *v2d, float x, float y)
Definition: view2d.cc:1946
void UI_view2d_scale_get(const struct View2D *v2d, float *r_x, float *r_y)
void UI_view2d_view_restore(const struct bContext *C)
void UI_view2d_view_ortho(const struct View2D *v2d)
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
void UI_view2d_dot_grid_draw(const struct View2D *v2d, int grid_color_id, float min_step, int grid_subdivisions)
void UI_view2d_scrollers_draw(struct View2D *v2d, const struct rcti *mask_custom)
void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y)
Definition: view2d.cc:1936
@ WM_GIZMOMAP_DRAWSTEP_2D
#define NC_WORLD
Definition: WM_types.h:337
#define ND_SHADING
Definition: WM_types.h:425
#define ND_WORLD
Definition: WM_types.h:401
#define NC_SCENE
Definition: WM_types.h:328
#define ND_NODES
Definition: WM_types.h:384
#define ND_MODIFIER
Definition: WM_types.h:411
#define NC_MATERIAL
Definition: WM_types.h:330
#define NC_LAMP
Definition: WM_types.h:332
#define NC_TEXTURE
Definition: WM_types.h:331
#define ND_LIGHTING
Definition: WM_types.h:431
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
#define NC_OBJECT
Definition: WM_types.h:329
void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
unsigned int U
Definition: btGjkEpa3.h:78
void sort(btMatrix3x3 &U, btVector3 &sigma, btMatrix3x3 &V, int t)
Helper function of 3X3 SVD for sorting singular values.
const void * get() const
const CPPType * type() const
Value lookup_default(const Key &key, const Value &default_value) const
Definition: BLI_map.hh:510
Value & lookup_or_add_as(ForwardKey &&key, ForwardValue &&...value)
Definition: BLI_map.hh:547
Value & lookup_or_add(const Key &key, const Value &value)
Definition: BLI_map.hh:530
int64_t size() const
Definition: BLI_map.hh:901
ItemIterator items() const
Definition: BLI_map.hh:859
bool is_empty() const
Definition: BLI_map.hh:911
constexpr const T & last(const int64_t n=0) const
Definition: BLI_span.hh:313
constexpr int64_t size() const
Definition: BLI_span.hh:240
constexpr IndexRange index_range() const
Definition: BLI_span.hh:401
constexpr bool is_empty() const
Definition: BLI_span.hh:248
constexpr bool is_empty() const
constexpr const char * data() const
int64_t size() const
Definition: BLI_vector.hh:694
void append(const T &value)
Definition: BLI_vector.hh:433
IndexRange index_range() const
Definition: BLI_vector.hh:920
Span< GeometryComponentType > supported_types() const
static const NodeLog * find_node_by_node_editor_context(const SpaceNode &snode, const bNode &node)
static const TreeLog * find_tree_by_node_editor_context(const SpaceNode &snode)
static const SocketLog * find_socket_by_node_editor_context(const SpaceNode &snode, const bNode &node, const bNodeSocket &socket)
void execution_time(std::chrono::microseconds exec_time)
const TreeLog * lookup_child_log(StringRef node_name) const
void foreach_node_log(FunctionRef< void(const NodeLog &)> fn) const
#define sinf(x)
Definition: cuda/compat.h:102
#define cosf(x)
Definition: cuda/compat.h:101
#define SELECT
OperationNode * node
const char * label
SyclQueue void void size_t num_bytes void
bNodeTree * ntree
#define str(s)
static const char * to_string(const Interpolation &interp)
Definition: gl_shader.cc:63
uint pos
void GPU_clear_color(float red, float green, float blue, float alpha)
#define GS(x)
Definition: iris.c:225
ccl_global float * buffer
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
const int state
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define floorf(x)
Definition: metal/compat.h:224
static unsigned a[3]
Definition: RandGen.cpp:78
static Array< uiBlock * > node_uiblocks_init(const bContext &C, Span< bNode * > nodes)
Definition: node_draw.cc:270
float node_socket_calculate_height(const bNodeSocket &socket)
Definition: node_edit.cc:95
void node_sort(bNodeTree &ntree)
Definition: node_draw.cc:215
void node_socket_add_tooltip(bNodeTree *ntree, bNode *node, bNodeSocket *sock, uiLayout *layout)
Definition: node_draw.cc:1090
int node_get_resize_cursor(NodeResizeDirection directions)
Definition: node_draw.cc:2508
static void node_socket_outline_color_get(const bool selected, const int socket_type, float r_outline_color[4])
Definition: node_draw.cc:747
void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor)
Definition: node_draw.cc:2522
static void node_draw(const bContext &C, ARegion &region, const SpaceNode &snode, bNodeTree &ntree, bNode &node, uiBlock &block, bNodeInstanceKey key)
Definition: node_draw.cc:2889
static void node_draw_preview(bNodePreview *preview, rctf *prv)
Definition: node_draw.cc:1258
static void node_draw_hidden(const bContext &C, const View2D &v2d, const SpaceNode &snode, bNodeTree &ntree, bNode &node, uiBlock &block)
Definition: node_draw.cc:2332
static char * named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
Definition: node_draw.cc:1762
static char * node_socket_get_tooltip(bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *socket)
Definition: node_draw.cc:1054
static void draw_nodetree(const bContext &C, ARegion &region, bNodeTree &ntree, bNodeInstanceKey parent_key)
Definition: node_draw.cc:3018
static void node_update_nodetree(const bContext &C, bNodeTree &ntree, Span< bNode * > nodes, Span< uiBlock * > blocks)
Definition: node_draw.cc:2662
static NodeExtraInfoRow row_from_used_named_attribute(const Map< std::string, eNamedAttrUsage > &usage_by_attribute_name)
Definition: node_draw.cc:1812
void node_draw_link_bezier(const bContext &C, const View2D &v2d, const SpaceNode &snode, const bNodeLink &link, const int th_col1, const int th_col2, const int th_col3, const bool selected)
Definition: drawnode.cc:1987
static void draw_background_color(const SpaceNode &snode)
Definition: node_draw.cc:3036
void nodelink_batch_end(SpaceNode &snode)
Definition: drawnode.cc:1935
static std::chrono::microseconds node_get_execution_time(const bNodeTree &ntree, const bNode &node, const SpaceNode &snode, int &node_count)
Definition: node_draw.cc:1675
static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, uiBlock &block)
Definition: node_draw.cc:314
void node_socket_color_get(const bContext &C, const bNodeTree &ntree, PointerRNA &node_ptr, const bNodeSocket &sock, float r_color[4])
Definition: node_draw.cc:764
void node_draw_link(const bContext &C, const View2D &v2d, const SpaceNode &snode, const bNodeLink &link, const bool selected)
Definition: drawnode.cc:2124
static void node_draw_mute_line(const bContext &C, const View2D &v2d, const SpaceNode &snode, const bNode &node)
Definition: node_draw.cc:658
static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss)
Definition: node_draw.cc:783
static void reroute_node_prepare_for_draw(bNode &node)
Definition: node_draw.cc:2640
static void node_draw_sockets(const View2D &v2d, const bContext &C, bNodeTree &ntree, bNode &node, uiBlock &block, const bool draw_outputs, const bool select_all)
Definition: node_draw.cc:1331
void draw_nodespace_back_pix(const bContext &C, ARegion &region, SpaceNode &snode, bNodeInstanceKey parent_key)
Definition: drawnode.cc:1501
static void frame_node_draw(const bContext &C, const ARegion &region, const SpaceNode &snode, bNodeTree &ntree, bNode &node, uiBlock &block)
Definition: node_draw.cc:2789
static void count_multi_input_socket_links(bNodeTree &ntree, SpaceNode &snode)
Definition: node_draw.cc:2561
NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y)
Definition: drawnode.cc:222
void nodelink_batch_start(SpaceNode &UNUSED(snode))
Definition: drawnode.cc:1930
static Vector< NodeExtraInfoRow > node_get_extra_info(const SpaceNode &snode, const bNode &node)
Definition: node_draw.cc:1885
static void node_draw_extra_info_row(const bNode &node, uiBlock &block, const rctf &rect, const int row, const NodeExtraInfoRow &extra_info_row)
Definition: node_draw.cc:1926
bool node_find_indicated_socket(SpaceNode &snode, bNode **nodep, bNodeSocket **sockp, const float2 &cursor, const eNodeSocketInOut in_out)
Definition: node_edit.cc:1226
static void node_draw_basis(const bContext &C, const View2D &v2d, const SpaceNode &snode, bNodeTree &ntree, bNode &node, uiBlock &block, bNodeInstanceKey key)
Definition: node_draw.cc:2041
Vector< ui::ContextPathItem > context_path_for_space_node(const bContext &C)
static void node_socket_draw_multi_input(const float color[4], const float color_outline[4], const float width, const float height, const int locx, const int locy)
Definition: node_draw.cc:719
static void node_update_hidden(bNode &node, uiBlock &block)
Definition: node_draw.cc:547
void node_select_single(bContext &C, bNode &node)
Definition: node_select.cc:487
static int node_error_type_to_icon(const geo_log::NodeWarningType type)
Definition: node_draw.cc:1533
static bool node_socket_has_tooltip(bNodeTree *ntree, bNodeSocket *socket)
Definition: node_draw.cc:1040
static std::optional< NodeExtraInfoRow > node_get_accessed_attributes_row(const SpaceNode &snode, const bNode &node)
Definition: node_draw.cc:1827
static void node_socket_draw(const bNodeSocket &sock, const float color[4], const float color_outline[4], float size, int locx, int locy, uint pos_id, uint col_id, uint shape_id, uint size_id, uint outline_col_id)
Definition: node_draw.cc:674
static void get_exec_time_other_nodes(const bNode &node, const SpaceNode &snode, std::chrono::microseconds &exec_time, int &node_count)
Definition: node_draw.cc:1645
static void node_draw_nodetree(const bContext &C, ARegion &region, SpaceNode &snode, bNodeTree &ntree, Span< bNode * > nodes, Span< uiBlock * > blocks, bNodeInstanceKey parent_key)
Definition: node_draw.cc:2916
static void reroute_node_draw(const bContext &C, ARegion &region, bNodeTree &ntree, bNode &node, uiBlock &block)
Definition: node_draw.cc:2842
static const float virtual_node_socket_outline_color[4]
Definition: node_draw.cc:745
float2 node_to_view(const bNode &node, const float2 &co)
Definition: node_draw.cc:284
void snode_set_context(const bContext &C)
Definition: node_edit.cc:618
static int node_get_colorid(const bNode &node)
Definition: node_draw.cc:614
static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv)
Definition: node_draw.cc:1310
static std::string node_get_execution_time_label(const SpaceNode &snode, const bNode &node)
Definition: node_draw.cc:1714
rctf node_frame_rect_inside(const bNode &node)
Definition: node_select.cc:88
static void frame_node_draw_label(const bNodeTree &ntree, const bNode &node, const SpaceNode &snode)
Definition: node_draw.cc:2702
static uint8_t node_error_type_priority(const geo_log::NodeWarningType type)
Definition: node_draw.cc:1548
void node_to_updated_rect(const bNode &node, rctf &r_rect)
Definition: node_draw.cc:291
void node_draw_space(const bContext &C, ARegion &region)
Definition: node_draw.cc:3054
static void node_draw_preview_background(rctf *rect)
Definition: node_draw.cc:1240
static void node_draw_shadow(const SpaceNode &snode, const bNode &node, const float radius, const float alpha)
Definition: node_draw.cc:1321
static void node_draw_extra_info_panel(const SpaceNode &snode, const bNode &node, uiBlock &block)
Definition: node_draw.cc:1984
static geo_log::NodeWarningType node_error_highest_priority(Span< geo_log::NodeWarning > warnings)
Definition: node_draw.cc:1563
static void draw_tree_path(const bContext &C, ARegion &region)
Definition: node_draw.cc:2976
static void node_add_error_message_button(const bContext &C, bNode &node, uiBlock &block, const rctf &rect, float &icon_offset)
Definition: node_draw.cc:1603
static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log, std::stringstream &ss, const nodes::decl::Geometry *geometry)
Definition: node_draw.cc:875
static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &value_log, std::stringstream &ss)
Definition: node_draw.cc:824
static std::optional< std::string > create_socket_inspection_string(bContext *C, bNode &node, bNodeSocket &socket)
Definition: node_draw.cc:1001
static bool compare_nodes(const bNode *a, const bNode *b)
Definition: node_draw.cc:159
static void node_socket_draw_nested(const bContext &C, bNodeTree &ntree, PointerRNA &node_ptr, uiBlock &block, bNodeSocket &sock, const uint pos_id, const uint col_id, const uint shape_id, const uint size_id, const uint outline_col_id, const float size, const bool selected)
Definition: node_draw.cc:1112
float2 node_from_view(const bNode &node, const float2 &co)
Definition: node_draw.cc:302
static char * node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
Definition: node_draw.cc:1581
static void frame_node_prepare_for_draw(bNode &node, Span< bNode * > nodes)
Definition: node_draw.cc:2592
static void snode_setup_v2d(SpaceNode &snode, ARegion &region, const float2 &center)
Definition: node_draw.cc:3005
void evaluate_constant_field(const GField &field, void *r_value)
Definition: field.cc:494
void template_breadcrumbs(uiLayout &layout, Span< ContextPathItem > context_path)
vec_base< float, 2 > float2
std::string to_string(const T &n)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static const pxr::TfToken preview("preview", pxr::TfToken::Immortal)
#define NODE_HEADER_ICON_SIZE
Definition: node_draw.cc:1601
void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
Definition: node_draw.cc:1186
void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select)
float ED_node_grid_size()
Definition: node_draw.cc:87
void ED_node_tag_update_id(ID *id)
Definition: node_draw.cc:117
static bNodeTree * node_tree_from_ID(ID *id)
Definition: node_draw.cc:105
void ED_node_tree_update(const bContext *C)
Definition: node_draw.cc:92
#define NODE_SOCK_OUTLINE_SCALE
Definition: node_intern.hh:120
#define NODE_MULTI_INPUT_LINK_GAP
Definition: node_intern.hh:121
#define BASIS_RAD
Definition: node_intern.hh:111
#define NODE_SOCKSIZE
Definition: node_intern.hh:118
#define NODE_WIDTH(node)
Definition: node_intern.hh:115
#define NODE_DYS
Definition: node_intern.hh:112
#define NODE_SOCKSIZE_DRAW_MULIPLIER
Definition: node_intern.hh:119
#define NODE_SOCKDY
Definition: node_intern.hh:114
#define NODE_MARGIN_X
Definition: node_intern.hh:117
#define HIDDEN_RAD
Definition: node_intern.hh:110
#define NODE_DY
Definition: node_intern.hh:113
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
Definition: rna_access.c:695
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
unsigned char uint8_t
Definition: stdint.h:78
unsigned __int64 uint64_t
Definition: stdint.h:90
struct wmGizmoMap * gizmo_map
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
struct StructRNA * type
Definition: RNA_types.h:37
void * data
Definition: RNA_types.h:38
int lines
Definition: BLF_api.h:369
SpaceNode_Runtime * runtime
ListBase treepath
struct bNodeTree * edittree
struct ID * id
SpaceNodeOverlay overlay
struct bNodeTree * nodetree
ListBase lines
void(* draw_color)(struct bContext *C, struct PointerRNA *ptr, struct PointerRNA *node_ptr, float *r_color)
Definition: BKE_node.h:154
bNodeSocketRuntimeHandle * runtime
struct bNodeSocketType * typeinfo
struct bNodeTree * nodetree
bNodeInstanceKey parent_key
float view_center[2]
char display_name[64]
float view_center[2]
ListBase nodes
ListBase links
struct bNode * next
Map< std::string, eNamedAttrUsage > usage_by_attribute
Definition: node_draw.cc:1759
Span< geo_log::NodeWarning > warnings
Definition: node_draw.cc:1578
std::unique_ptr< bNodeLinkDrag > linkdrag
Definition: node_intern.hh:93
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
int ymin
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
uiFontStyle widgetlabel
int xy[2]
Definition: WM_types.h:682
struct wmEvent * eventstate
float max
void WM_cursor_set(wmWindow *win, int curs)
Definition: wm_cursors.c:126
@ WM_CURSOR_NSEW_SCROLL
Definition: wm_cursors.h:51
@ WM_CURSOR_DEFAULT
Definition: wm_cursors.h:18
@ WM_CURSOR_Y_MOVE
Definition: wm_cursors.h:39
@ WM_CURSOR_EDIT
Definition: wm_cursors.h:22
@ WM_CURSOR_X_MOVE
Definition: wm_cursors.h:38
GPUViewport * WM_draw_region_get_viewport(ARegion *region)
Definition: wm_draw.c:846
void WM_main_add_notifier(unsigned int type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
PointerRNA * ptr
Definition: wm_files.c:3480
void WM_gizmomap_draw(wmGizmoMap *gzmap, const bContext *C, const eWM_GizmoFlagMapDrawStep drawstep)
Definition: wm_gizmo_map.c:483
void wmOrtho2_pixelspace(const float x, const float y)
Definition: wm_subwindow.c:108
void wmOrtho2_region_pixelspace(const ARegion *region)
Definition: wm_subwindow.c:103