Cleanup: reorder report argument for pointer assignment
[blender.git] / source / blender / editors / space_node / node_add.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup spnode
22  */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "DNA_node_types.h"
27
28 #include "BLI_listbase.h"
29 #include "BLI_math.h"
30
31 #include "BLT_translation.h"
32
33 #include "BKE_context.h"
34 #include "BKE_image.h"
35 #include "BKE_library.h"
36 #include "BKE_main.h"
37 #include "BKE_node.h"
38 #include "BKE_report.h"
39 #include "BKE_scene.h"
40 #include "BKE_texture.h"
41
42 #include "ED_node.h" /* own include */
43 #include "ED_screen.h"
44 #include "ED_render.h"
45
46 #include "RNA_access.h"
47 #include "RNA_define.h"
48 #include "RNA_enum_types.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "UI_view2d.h"
54
55 #include "node_intern.h" /* own include */
56
57 /**
58  * XXX Does some additional initialization on top of #nodeAddNode
59  * Can be used with both custom and static nodes,
60  * if `idname == NULL` the static int type will be used instead.
61  */
62 bNode *node_add_node(const bContext *C, const char *idname, int type, float locx, float locy)
63 {
64   SpaceNode *snode = CTX_wm_space_node(C);
65   Main *bmain = CTX_data_main(C);
66   bNode *node = NULL;
67
68   node_deselect_all(snode);
69
70   if (idname) {
71     node = nodeAddNode(C, snode->edittree, idname);
72   }
73   else {
74     node = nodeAddStaticNode(C, snode->edittree, type);
75   }
76   BLI_assert(node && node->typeinfo);
77
78   /* Position mouse in node header. */
79   node->locx = locx - NODE_DY * 1.5f / UI_DPI_FAC;
80   node->locy = locy + NODE_DY * 0.5f / UI_DPI_FAC;
81
82   nodeSetSelected(node, true);
83
84   ntreeUpdateTree(bmain, snode->edittree);
85   ED_node_set_active(bmain, snode->edittree, node);
86
87   snode_update(snode, node);
88
89   if (snode->nodetree->type == NTREE_TEXTURE) {
90     ntreeTexCheckCyclics(snode->edittree);
91   }
92
93   return node;
94 }
95
96 /* ********************** Add reroute operator ***************** */
97 static bool add_reroute_intersect_check(bNodeLink *link,
98                                         float mcoords[][2],
99                                         int tot,
100                                         float result[2])
101 {
102   float coord_array[NODE_LINK_RESOL + 1][2];
103   int i, b;
104
105   if (node_link_bezier_points(NULL, NULL, link, coord_array, NODE_LINK_RESOL)) {
106
107     for (i = 0; i < tot - 1; i++) {
108       for (b = 0; b < NODE_LINK_RESOL; b++) {
109         if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) {
110           result[0] = (mcoords[i][0] + mcoords[i + 1][0]) / 2.0f;
111           result[1] = (mcoords[i][1] + mcoords[i + 1][1]) / 2.0f;
112           return 1;
113         }
114       }
115     }
116   }
117   return 0;
118 }
119
120 typedef struct bNodeSocketLink {
121   struct bNodeSocketLink *next, *prev;
122
123   struct bNodeSocket *sock;
124   struct bNodeLink *link;
125   float point[2];
126 } bNodeSocketLink;
127
128 static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb,
129                                                        bNodeSocket *sock,
130                                                        bNodeLink *link,
131                                                        const float point[2])
132 {
133   bNodeSocketLink *socklink, *prev;
134
135   socklink = MEM_callocN(sizeof(bNodeSocketLink), "socket link");
136   socklink->sock = sock;
137   socklink->link = link;
138   copy_v2_v2(socklink->point, point);
139
140   for (prev = lb->last; prev; prev = prev->prev) {
141     if (prev->sock == sock) {
142       break;
143     }
144   }
145   BLI_insertlinkafter(lb, prev, socklink);
146   return socklink;
147 }
148
149 static bNodeSocketLink *add_reroute_do_socket_section(bContext *C,
150                                                       bNodeSocketLink *socklink,
151                                                       int in_out)
152 {
153   SpaceNode *snode = CTX_wm_space_node(C);
154   bNodeTree *ntree = snode->edittree;
155   bNode *reroute_node = NULL;
156   bNodeSocket *cursock = socklink->sock;
157   float insert_point[2];
158   int num_links;
159
160   zero_v2(insert_point);
161   num_links = 0;
162
163   while (socklink && socklink->sock == cursock) {
164     if (!(socklink->link->flag & NODE_LINK_TEST)) {
165       socklink->link->flag |= NODE_LINK_TEST;
166
167       /* create the reroute node for this cursock */
168       if (!reroute_node) {
169         reroute_node = nodeAddStaticNode(C, ntree, NODE_REROUTE);
170
171         /* add a single link to/from the reroute node to replace multiple links */
172         if (in_out == SOCK_OUT) {
173           nodeAddLink(ntree,
174                       socklink->link->fromnode,
175                       socklink->link->fromsock,
176                       reroute_node,
177                       reroute_node->inputs.first);
178         }
179         else {
180           nodeAddLink(ntree,
181                       reroute_node,
182                       reroute_node->outputs.first,
183                       socklink->link->tonode,
184                       socklink->link->tosock);
185         }
186       }
187
188       /* insert the reroute node into the link */
189       if (in_out == SOCK_OUT) {
190         socklink->link->fromnode = reroute_node;
191         socklink->link->fromsock = reroute_node->outputs.first;
192       }
193       else {
194         socklink->link->tonode = reroute_node;
195         socklink->link->tosock = reroute_node->inputs.first;
196       }
197
198       add_v2_v2(insert_point, socklink->point);
199       num_links++;
200     }
201     socklink = socklink->next;
202   }
203
204   if (num_links > 0) {
205     /* average cut point from shared links */
206     mul_v2_fl(insert_point, 1.0f / num_links);
207
208     reroute_node->locx = insert_point[0] / UI_DPI_FAC;
209     reroute_node->locy = insert_point[1] / UI_DPI_FAC;
210   }
211
212   return socklink;
213 }
214
215 static int add_reroute_exec(bContext *C, wmOperator *op)
216 {
217   SpaceNode *snode = CTX_wm_space_node(C);
218   ARegion *ar = CTX_wm_region(C);
219   bNodeTree *ntree = snode->edittree;
220   float mcoords[256][2];
221   int i = 0;
222
223   /* Get the cut path */
224   RNA_BEGIN (op->ptr, itemptr, "path") {
225     float loc[2];
226
227     RNA_float_get_array(&itemptr, "loc", loc);
228     UI_view2d_region_to_view(
229         &ar->v2d, (short)loc[0], (short)loc[1], &mcoords[i][0], &mcoords[i][1]);
230     i++;
231     if (i >= 256) {
232       break;
233     }
234   }
235   RNA_END;
236
237   if (i > 1) {
238     ListBase output_links, input_links;
239     bNodeLink *link;
240     bNodeSocketLink *socklink;
241     float insert_point[2];
242
243     /* always first */
244     ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
245
246     node_deselect_all(snode);
247
248     /* Find cut links and sort them by sockets */
249     BLI_listbase_clear(&output_links);
250     BLI_listbase_clear(&input_links);
251
252     for (link = ntree->links.first; link; link = link->next) {
253       if (nodeLinkIsHidden(link)) {
254         continue;
255       }
256       if (add_reroute_intersect_check(link, mcoords, i, insert_point)) {
257         add_reroute_insert_socket_link(&output_links, link->fromsock, link, insert_point);
258         add_reroute_insert_socket_link(&input_links, link->tosock, link, insert_point);
259
260         /* Clear flag */
261         link->flag &= ~NODE_LINK_TEST;
262       }
263     }
264
265     /* Create reroute nodes for intersected links.
266      * Only one reroute if links share the same input/output socket.
267      */
268     socklink = output_links.first;
269     while (socklink) {
270       socklink = add_reroute_do_socket_section(C, socklink, SOCK_OUT);
271     }
272     socklink = input_links.first;
273     while (socklink) {
274       socklink = add_reroute_do_socket_section(C, socklink, SOCK_IN);
275     }
276
277     BLI_freelistN(&output_links);
278     BLI_freelistN(&input_links);
279
280     /* always last */
281     ntreeUpdateTree(CTX_data_main(C), ntree);
282     snode_notify(C, snode);
283     snode_dag_update(C, snode);
284
285     return OPERATOR_FINISHED;
286   }
287
288   return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
289 }
290
291 void NODE_OT_add_reroute(wmOperatorType *ot)
292 {
293   ot->name = "Add Reroute";
294   ot->idname = "NODE_OT_add_reroute";
295   ot->description = "Add a reroute node";
296
297   ot->invoke = WM_gesture_lines_invoke;
298   ot->modal = WM_gesture_lines_modal;
299   ot->exec = add_reroute_exec;
300   ot->cancel = WM_gesture_lines_cancel;
301
302   ot->poll = ED_operator_node_editable;
303
304   /* flags */
305   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
306
307   /* properties */
308   PropertyRNA *prop;
309   prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
310   RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
311   /* internal */
312   RNA_def_int(ot->srna, "cursor", BC_CROSSCURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
313 }
314
315 /* ****************** Add File Node Operator  ******************* */
316
317 static int node_add_file_exec(bContext *C, wmOperator *op)
318 {
319   Main *bmain = CTX_data_main(C);
320   SpaceNode *snode = CTX_wm_space_node(C);
321   bNode *node;
322   Image *ima;
323   int type = 0;
324
325   ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
326   if (!ima) {
327     return OPERATOR_CANCELLED;
328   }
329
330   switch (snode->nodetree->type) {
331     case NTREE_SHADER:
332       type = SH_NODE_TEX_IMAGE;
333       break;
334     case NTREE_TEXTURE:
335       type = TEX_NODE_IMAGE;
336       break;
337     case NTREE_COMPOSIT:
338       type = CMP_NODE_IMAGE;
339       break;
340     default:
341       return OPERATOR_CANCELLED;
342   }
343
344   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
345
346   node = node_add_node(C, NULL, type, snode->cursor[0], snode->cursor[1]);
347
348   if (!node) {
349     BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
350     return OPERATOR_CANCELLED;
351   }
352
353   node->id = (ID *)ima;
354
355   /* When adding new image file via drag-drop we need to load imbuf in order
356    * to get proper image source.
357    */
358   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
359     BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
360     WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
361   }
362
363   snode_notify(C, snode);
364   snode_dag_update(C, snode);
365
366   return OPERATOR_FINISHED;
367 }
368
369 static int node_add_file_invoke(bContext *C, wmOperator *op, const wmEvent *event)
370 {
371   ARegion *ar = CTX_wm_region(C);
372   SpaceNode *snode = CTX_wm_space_node(C);
373
374   /* convert mouse coordinates to v2d space */
375   UI_view2d_region_to_view(
376       &ar->v2d, event->mval[0], event->mval[1], &snode->cursor[0], &snode->cursor[1]);
377
378   snode->cursor[0] /= UI_DPI_FAC;
379   snode->cursor[1] /= UI_DPI_FAC;
380
381   if (RNA_struct_property_is_set(op->ptr, "filepath") ||
382       RNA_struct_property_is_set(op->ptr, "name")) {
383     return node_add_file_exec(C, op);
384   }
385   else {
386     return WM_operator_filesel(C, op, event);
387   }
388 }
389
390 void NODE_OT_add_file(wmOperatorType *ot)
391 {
392   /* identifiers */
393   ot->name = "Add File Node";
394   ot->description = "Add a file node to the current node editor";
395   ot->idname = "NODE_OT_add_file";
396
397   /* callbacks */
398   ot->exec = node_add_file_exec;
399   ot->invoke = node_add_file_invoke;
400   ot->poll = ED_operator_node_editable;
401
402   /* flags */
403   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
404
405   WM_operator_properties_filesel(ot,
406                                  FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
407                                  FILE_SPECIAL,
408                                  FILE_OPENFILE,
409                                  WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
410                                  FILE_DEFAULTDISPLAY,
411                                  FILE_SORT_ALPHA);
412   RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
413 }
414
415 /* ****************** Add Mask Node Operator  ******************* */
416
417 static bool node_add_mask_poll(bContext *C)
418 {
419   SpaceNode *snode = CTX_wm_space_node(C);
420
421   return ED_operator_node_editable(C) && snode->nodetree->type == NTREE_COMPOSIT;
422 }
423
424 static int node_add_mask_exec(bContext *C, wmOperator *op)
425 {
426   Main *bmain = CTX_data_main(C);
427   SpaceNode *snode = CTX_wm_space_node(C);
428   bNode *node;
429   ID *mask = NULL;
430
431   /* check input variables */
432   char name[MAX_ID_NAME - 2];
433   RNA_string_get(op->ptr, "name", name);
434   mask = BKE_libblock_find_name(bmain, ID_MSK, name);
435   if (!mask) {
436     BKE_reportf(op->reports, RPT_ERROR, "Mask '%s' not found", name);
437     return OPERATOR_CANCELLED;
438   }
439
440   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
441
442   node = node_add_node(C, NULL, CMP_NODE_MASK, snode->cursor[0], snode->cursor[1]);
443
444   if (!node) {
445     BKE_report(op->reports, RPT_WARNING, "Could not add a mask node");
446     return OPERATOR_CANCELLED;
447   }
448
449   node->id = mask;
450   id_us_plus(mask);
451
452   snode_notify(C, snode);
453   snode_dag_update(C, snode);
454
455   return OPERATOR_FINISHED;
456 }
457
458 void NODE_OT_add_mask(wmOperatorType *ot)
459 {
460   /* identifiers */
461   ot->name = "Add Mask Node";
462   ot->description = "Add a mask node to the current node editor";
463   ot->idname = "NODE_OT_add_mask";
464
465   /* callbacks */
466   ot->exec = node_add_mask_exec;
467   ot->poll = node_add_mask_poll;
468
469   /* flags */
470   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
471
472   RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
473 }
474
475 /********************** New node tree operator *********************/
476
477 static int new_node_tree_exec(bContext *C, wmOperator *op)
478 {
479   SpaceNode *snode = CTX_wm_space_node(C);
480   Main *bmain = CTX_data_main(C);
481   bNodeTree *ntree;
482   PointerRNA ptr, idptr;
483   PropertyRNA *prop;
484   const char *idname;
485   char treename_buf[MAX_ID_NAME - 2];
486   const char *treename;
487
488   if (RNA_struct_property_is_set(op->ptr, "type")) {
489     prop = RNA_struct_find_property(op->ptr, "type");
490     RNA_property_enum_identifier(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &idname);
491   }
492   else if (snode) {
493     idname = snode->tree_idname;
494   }
495   else {
496     return OPERATOR_CANCELLED;
497   }
498
499   if (RNA_struct_property_is_set(op->ptr, "name")) {
500     RNA_string_get(op->ptr, "name", treename_buf);
501     treename = treename_buf;
502   }
503   else {
504     treename = DATA_("NodeTree");
505   }
506
507   if (!ntreeTypeFind(idname)) {
508     BKE_reportf(op->reports, RPT_ERROR, "Node tree type %s undefined", idname);
509     return OPERATOR_CANCELLED;
510   }
511
512   ntree = ntreeAddTree(bmain, treename, idname);
513
514   /* hook into UI */
515   UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
516
517   if (prop) {
518     /* RNA_property_pointer_set increases the user count,
519      * fixed here as the editor is the initial user.
520      */
521     id_us_min(&ntree->id);
522
523     RNA_id_pointer_create(&ntree->id, &idptr);
524     RNA_property_pointer_set(&ptr, prop, idptr, NULL);
525     RNA_property_update(C, &ptr, prop);
526   }
527   else if (snode) {
528     snode->nodetree = ntree;
529
530     ED_node_tree_update(C);
531   }
532
533   return OPERATOR_FINISHED;
534 }
535
536 static const EnumPropertyItem *new_node_tree_type_itemf(bContext *UNUSED(C),
537                                                         PointerRNA *UNUSED(ptr),
538                                                         PropertyRNA *UNUSED(prop),
539                                                         bool *r_free)
540 {
541   return rna_node_tree_type_itemf(NULL, NULL, r_free);
542 }
543
544 void NODE_OT_new_node_tree(wmOperatorType *ot)
545 {
546   PropertyRNA *prop;
547
548   /* identifiers */
549   ot->name = "New Node Tree";
550   ot->idname = "NODE_OT_new_node_tree";
551   ot->description = "Create a new node tree";
552
553   /* api callbacks */
554   ot->exec = new_node_tree_exec;
555
556   /* flags */
557   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
558
559   prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Tree Type", "");
560   RNA_def_enum_funcs(prop, new_node_tree_type_itemf);
561   RNA_def_string(ot->srna, "name", "NodeTree", MAX_ID_NAME - 2, "Name", "");
562 }