Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / render / render_shading.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16  *
17  * The Original Code is Copyright (C) 2009 Blender Foundation.
18  * All rights reserved.
19  *
20  * Contributor(s): Blender Foundation
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/render/render_shading.c
26  *  \ingroup edrend
27  */
28
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_curve_types.h"
35 #include "DNA_lamp_types.h"
36 #include "DNA_material_types.h"
37 #include "DNA_node_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_particle_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_space_types.h"
42 #include "DNA_world_types.h"
43
44 #include "BLI_utildefines.h"
45 #include "BLI_listbase.h"
46 #include "BLI_math_vector.h"
47
48 #include "BLT_translation.h"
49
50 #include "BKE_animsys.h"
51 #include "BKE_context.h"
52 #include "BKE_curve.h"
53 #include "BKE_font.h"
54 #include "BKE_global.h"
55 #include "BKE_image.h"
56 #include "BKE_layer.h"
57 #include "BKE_library.h"
58 #include "BKE_linestyle.h"
59 #include "BKE_main.h"
60 #include "BKE_material.h"
61 #include "BKE_paint.h"
62 #include "BKE_report.h"
63 #include "BKE_scene.h"
64 #include "BKE_texture.h"
65 #include "BKE_workspace.h"
66 #include "BKE_world.h"
67 #include "BKE_editmesh.h"
68
69 #include "DEG_depsgraph.h"
70 #include "DEG_depsgraph_build.h"
71
72 #ifdef WITH_FREESTYLE
73 #  include "BKE_freestyle.h"
74 #  include "FRS_freestyle.h"
75 #  include "RNA_enum_types.h"
76 #endif
77
78 #include "RNA_access.h"
79
80 #include "WM_api.h"
81 #include "WM_types.h"
82
83 #include "ED_object.h"
84 #include "ED_curve.h"
85 #include "ED_mesh.h"
86 #include "ED_node.h"
87 #include "ED_render.h"
88 #include "ED_scene.h"
89 #include "ED_screen.h"
90
91 #include "RNA_define.h"
92
93 #include "UI_interface.h"
94
95 #include "RE_pipeline.h"
96
97 #include "render_intern.h"  // own include
98
99 /********************** material slot operators *********************/
100
101 static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
102 {
103         Main *bmain = CTX_data_main(C);
104         Object *ob = ED_object_context(C);
105
106         if (!ob)
107                 return OPERATOR_CANCELLED;
108
109         BKE_object_material_slot_add(bmain, ob);
110
111         if (ob->mode & OB_MODE_TEXTURE_PAINT) {
112                 Scene *scene = CTX_data_scene(C);
113                 BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
114                 WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
115         }
116
117         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
118         WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
119         WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_PREVIEW, ob);
120
121         return OPERATOR_FINISHED;
122 }
123
124 void OBJECT_OT_material_slot_add(wmOperatorType *ot)
125 {
126         /* identifiers */
127         ot->name = "Add Material Slot";
128         ot->idname = "OBJECT_OT_material_slot_add";
129         ot->description = "Add a new material slot";
130
131         /* api callbacks */
132         ot->exec = material_slot_add_exec;
133         ot->poll = ED_operator_object_active_editable;
134
135         /* flags */
136         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
137 }
138
139 static int material_slot_remove_exec(bContext *C, wmOperator *op)
140 {
141         Object *ob = ED_object_context(C);
142
143         if (!ob)
144                 return OPERATOR_CANCELLED;
145
146         /* Removing material slots in edit mode screws things up, see bug #21822.*/
147         if (ob == CTX_data_edit_object(C)) {
148                 BKE_report(op->reports, RPT_ERROR, "Unable to remove material slot in edit mode");
149                 return OPERATOR_CANCELLED;
150         }
151
152         BKE_object_material_slot_remove(CTX_data_main(C), ob);
153
154         if (ob->mode & OB_MODE_TEXTURE_PAINT) {
155                 Scene *scene = CTX_data_scene(C);
156                 BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
157                 WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
158         }
159
160         DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
161         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
162         WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
163         WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_PREVIEW, ob);
164
165         return OPERATOR_FINISHED;
166 }
167
168 void OBJECT_OT_material_slot_remove(wmOperatorType *ot)
169 {
170         /* identifiers */
171         ot->name = "Remove Material Slot";
172         ot->idname = "OBJECT_OT_material_slot_remove";
173         ot->description = "Remove the selected material slot";
174
175         /* api callbacks */
176         ot->exec = material_slot_remove_exec;
177         ot->poll = ED_operator_object_active_editable;
178
179         /* flags */
180         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
181 }
182
183 static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
184 {
185         Object *ob = ED_object_context(C);
186
187         if (!ob)
188                 return OPERATOR_CANCELLED;
189
190         if (ob && ob->actcol > 0) {
191                 if (ob->type == OB_MESH) {
192                         BMEditMesh *em = BKE_editmesh_from_object(ob);
193                         BMFace *efa;
194                         BMIter iter;
195
196                         if (em) {
197                                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
198                                         if (BM_elem_flag_test(efa, BM_ELEM_SELECT))
199                                                 efa->mat_nr = ob->actcol - 1;
200                                 }
201                         }
202                 }
203                 else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
204                         Nurb *nu;
205                         ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data);
206
207                         if (nurbs) {
208                                 for (nu = nurbs->first; nu; nu = nu->next) {
209                                         if (ED_curve_nurb_select_check(ob->data, nu)) {
210                                                 nu->mat_nr = ob->actcol - 1;
211                                         }
212                                 }
213                         }
214                 }
215                 else if (ob->type == OB_FONT) {
216                         EditFont *ef = ((Curve *)ob->data)->editfont;
217                         int i, selstart, selend;
218
219                         if (ef && BKE_vfont_select_get(ob, &selstart, &selend)) {
220                                 for (i = selstart; i <= selend; i++)
221                                         ef->textbufinfo[i].mat_nr = ob->actcol;
222                         }
223                 }
224         }
225
226         DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
227         WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
228
229         return OPERATOR_FINISHED;
230 }
231
232 void OBJECT_OT_material_slot_assign(wmOperatorType *ot)
233 {
234         /* identifiers */
235         ot->name = "Assign Material Slot";
236         ot->idname = "OBJECT_OT_material_slot_assign";
237         ot->description = "Assign active material slot to selection";
238
239         /* api callbacks */
240         ot->exec = material_slot_assign_exec;
241         ot->poll = ED_operator_object_active_editable;
242
243         /* flags */
244         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
245 }
246
247 static int material_slot_de_select(bContext *C, bool select)
248 {
249         Object *ob = ED_object_context(C);
250
251         if (!ob)
252                 return OPERATOR_CANCELLED;
253
254         if (ob->type == OB_MESH) {
255                 BMEditMesh *em = BKE_editmesh_from_object(ob);
256
257                 if (em) {
258                         EDBM_deselect_by_material(em, ob->actcol - 1, select);
259                 }
260         }
261         else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
262                 ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data);
263                 Nurb *nu;
264                 BPoint *bp;
265                 BezTriple *bezt;
266                 int a;
267
268                 if (nurbs) {
269                         for (nu = nurbs->first; nu; nu = nu->next) {
270                                 if (nu->mat_nr == ob->actcol - 1) {
271                                         if (nu->bezt) {
272                                                 a = nu->pntsu;
273                                                 bezt = nu->bezt;
274                                                 while (a--) {
275                                                         if (bezt->hide == 0) {
276                                                                 if (select) {
277                                                                         bezt->f1 |= SELECT;
278                                                                         bezt->f2 |= SELECT;
279                                                                         bezt->f3 |= SELECT;
280                                                                 }
281                                                                 else {
282                                                                         bezt->f1 &= ~SELECT;
283                                                                         bezt->f2 &= ~SELECT;
284                                                                         bezt->f3 &= ~SELECT;
285                                                                 }
286                                                         }
287                                                         bezt++;
288                                                 }
289                                         }
290                                         else if (nu->bp) {
291                                                 a = nu->pntsu * nu->pntsv;
292                                                 bp = nu->bp;
293                                                 while (a--) {
294                                                         if (bp->hide == 0) {
295                                                                 if (select) bp->f1 |= SELECT;
296                                                                 else bp->f1 &= ~SELECT;
297                                                         }
298                                                         bp++;
299                                                 }
300                                         }
301                                 }
302                         }
303                 }
304         }
305
306         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
307
308         return OPERATOR_FINISHED;
309 }
310
311 static int material_slot_select_exec(bContext *C, wmOperator *UNUSED(op))
312 {
313         return material_slot_de_select(C, true);
314 }
315
316 void OBJECT_OT_material_slot_select(wmOperatorType *ot)
317 {
318         /* identifiers */
319         ot->name = "Select Material Slot";
320         ot->idname = "OBJECT_OT_material_slot_select";
321         ot->description = "Select by active material slot";
322
323         /* api callbacks */
324         ot->exec = material_slot_select_exec;
325
326         /* flags */
327         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
328 }
329
330 static int material_slot_deselect_exec(bContext *C, wmOperator *UNUSED(op))
331 {
332         return material_slot_de_select(C, false);
333 }
334
335 void OBJECT_OT_material_slot_deselect(wmOperatorType *ot)
336 {
337         /* identifiers */
338         ot->name = "Deselect Material Slot";
339         ot->idname = "OBJECT_OT_material_slot_deselect";
340         ot->description = "Deselect by active material slot";
341
342         /* api callbacks */
343         ot->exec = material_slot_deselect_exec;
344
345         /* flags */
346         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
347 }
348
349
350 static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
351 {
352         Main *bmain = CTX_data_main(C);
353         Object *ob = ED_object_context(C);
354         Material ***matar;
355
356         if (!ob || !(matar = give_matarar(ob)))
357                 return OPERATOR_CANCELLED;
358
359         CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects)
360         {
361                 if (ob != ob_iter && give_matarar(ob_iter)) {
362                         if (ob->data != ob_iter->data)
363                                 assign_matarar(bmain, ob_iter, matar, ob->totcol);
364
365                         if (ob_iter->totcol == ob->totcol) {
366                                 ob_iter->actcol = ob->actcol;
367                                 DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA);
368                                 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter);
369                         }
370                 }
371         }
372         CTX_DATA_END;
373
374         return OPERATOR_FINISHED;
375 }
376
377
378 void OBJECT_OT_material_slot_copy(wmOperatorType *ot)
379 {
380         /* identifiers */
381         ot->name = "Copy Material to Others";
382         ot->idname = "OBJECT_OT_material_slot_copy";
383         ot->description = "Copies materials to other selected objects";
384
385         /* api callbacks */
386         ot->exec = material_slot_copy_exec;
387
388         /* flags */
389         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
390 }
391
392 static int material_slot_move_exec(bContext *C, wmOperator *op)
393 {
394         Object *ob = ED_object_context(C);
395
396         unsigned int *slot_remap;
397         int index_pair[2];
398
399         int dir = RNA_enum_get(op->ptr, "direction");
400
401         if (!ob || ob->totcol < 2) {
402                 return OPERATOR_CANCELLED;
403         }
404
405         /* up */
406         if (dir == 1 && ob->actcol > 1) {
407                 index_pair[0] = ob->actcol - 2;
408                 index_pair[1] = ob->actcol - 1;
409                 ob->actcol--;
410         }
411         /* down */
412         else if (dir == -1 && ob->actcol < ob->totcol) {
413                 index_pair[0] = ob->actcol - 1;
414                 index_pair[1] = ob->actcol - 0;
415                 ob->actcol++;
416         }
417         else {
418                 return OPERATOR_CANCELLED;
419         }
420
421         slot_remap = MEM_mallocN(sizeof(unsigned int) * ob->totcol, __func__);
422
423         range_vn_u(slot_remap, ob->totcol, 0);
424
425         slot_remap[index_pair[0]] = index_pair[1];
426         slot_remap[index_pair[1]] = index_pair[0];
427
428         BKE_material_remap_object(ob, slot_remap);
429
430         MEM_freeN(slot_remap);
431
432         DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
433         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
434         WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob);
435
436         return OPERATOR_FINISHED;
437 }
438
439 void OBJECT_OT_material_slot_move(wmOperatorType *ot)
440 {
441         static const EnumPropertyItem material_slot_move[] = {
442                 {1, "UP", 0, "Up", ""},
443                 {-1, "DOWN", 0, "Down", ""},
444                 {0, NULL, 0, NULL, NULL}
445         };
446
447         /* identifiers */
448         ot->name = "Move Material";
449         ot->idname = "OBJECT_OT_material_slot_move";
450         ot->description = "Move the active material up/down in the list";
451
452         /* api callbacks */
453         ot->exec = material_slot_move_exec;
454
455         /* flags */
456         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
457
458         RNA_def_enum(ot->srna, "direction", material_slot_move, 0, "Direction",
459                      "Direction to move the active material towards");
460 }
461
462 /********************** new material operator *********************/
463
464 static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
465 {
466         Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
467         Main *bmain = CTX_data_main(C);
468         PointerRNA ptr, idptr;
469         PropertyRNA *prop;
470
471         /* add or copy material */
472         if (ma) {
473                 ma = BKE_material_copy(bmain, ma);
474         }
475         else {
476                 ma = BKE_material_add(bmain, DATA_("Material"));
477                 ED_node_shader_default(C, &ma->id);
478                 ma->use_nodes = true;
479         }
480
481         /* hook into UI */
482         UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
483
484         if (prop) {
485                 /* when creating new ID blocks, use is already 1, but RNA
486                  * pointer use also increases user, so this compensates it */
487                 id_us_min(&ma->id);
488
489                 RNA_id_pointer_create(&ma->id, &idptr);
490                 RNA_property_pointer_set(&ptr, prop, idptr);
491                 RNA_property_update(C, &ptr, prop);
492         }
493
494         WM_event_add_notifier(C, NC_MATERIAL | NA_ADDED, ma);
495
496         return OPERATOR_FINISHED;
497 }
498
499 void MATERIAL_OT_new(wmOperatorType *ot)
500 {
501         /* identifiers */
502         ot->name = "New Material";
503         ot->idname = "MATERIAL_OT_new";
504         ot->description = "Add a new material";
505
506         /* api callbacks */
507         ot->exec = new_material_exec;
508
509         /* flags */
510         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
511 }
512
513 /********************** new texture operator *********************/
514
515 static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
516 {
517         Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
518         Main *bmain = CTX_data_main(C);
519         PointerRNA ptr, idptr;
520         PropertyRNA *prop;
521
522         /* add or copy texture */
523         if (tex) {
524                 tex = BKE_texture_copy(bmain, tex);
525         }
526         else {
527                 tex = BKE_texture_add(bmain, DATA_("Texture"));
528         }
529
530         /* hook into UI */
531         UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
532
533         if (prop) {
534                 /* when creating new ID blocks, use is already 1, but RNA
535                  * pointer use also increases user, so this compensates it */
536                 id_us_min(&tex->id);
537
538                 RNA_id_pointer_create(&tex->id, &idptr);
539                 RNA_property_pointer_set(&ptr, prop, idptr);
540                 RNA_property_update(C, &ptr, prop);
541         }
542
543         WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, tex);
544
545         return OPERATOR_FINISHED;
546 }
547
548 void TEXTURE_OT_new(wmOperatorType *ot)
549 {
550         /* identifiers */
551         ot->name = "New Texture";
552         ot->idname = "TEXTURE_OT_new";
553         ot->description = "Add a new texture";
554
555         /* api callbacks */
556         ot->exec = new_texture_exec;
557
558         /* flags */
559         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
560 }
561
562 /********************** new world operator *********************/
563
564 static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
565 {
566         World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
567         Main *bmain = CTX_data_main(C);
568         PointerRNA ptr, idptr;
569         PropertyRNA *prop;
570
571         /* add or copy world */
572         if (wo) {
573                 wo = BKE_world_copy(bmain, wo);
574         }
575         else {
576                 wo = BKE_world_add(bmain, DATA_("World"));
577                 ED_node_shader_default(C, &wo->id);
578                 wo->use_nodes = true;
579         }
580
581         /* hook into UI */
582         UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
583
584         if (prop) {
585                 /* when creating new ID blocks, use is already 1, but RNA
586                  * pointer use also increases user, so this compensates it */
587                 id_us_min(&wo->id);
588
589                 RNA_id_pointer_create(&wo->id, &idptr);
590                 RNA_property_pointer_set(&ptr, prop, idptr);
591                 RNA_property_update(C, &ptr, prop);
592         }
593
594         WM_event_add_notifier(C, NC_WORLD | NA_ADDED, wo);
595
596         return OPERATOR_FINISHED;
597 }
598
599 void WORLD_OT_new(wmOperatorType *ot)
600 {
601         /* identifiers */
602         ot->name = "New World";
603         ot->idname = "WORLD_OT_new";
604         ot->description = "Create a new world Data-Block";
605
606         /* api callbacks */
607         ot->exec = new_world_exec;
608
609         /* flags */
610         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
611 }
612
613 /********************** render layer operators *********************/
614
615 static int view_layer_add_exec(bContext *C, wmOperator *UNUSED(op))
616 {
617         WorkSpace *workspace = CTX_wm_workspace(C);
618         Scene *scene = CTX_data_scene(C);
619         ViewLayer *view_layer = BKE_view_layer_add(scene, NULL);
620
621         if (workspace) {
622                 BKE_workspace_view_layer_set(workspace, view_layer, scene);
623         }
624
625         DEG_id_tag_update(&scene->id, 0);
626         DEG_relations_tag_update(CTX_data_main(C));
627         WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
628
629         return OPERATOR_FINISHED;
630 }
631
632 void SCENE_OT_view_layer_add(wmOperatorType *ot)
633 {
634         /* identifiers */
635         ot->name = "Add View Layer";
636         ot->idname = "SCENE_OT_view_layer_add";
637         ot->description = "Add a view layer";
638
639         /* api callbacks */
640         ot->exec = view_layer_add_exec;
641
642         /* flags */
643         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
644 }
645
646 static int view_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
647 {
648         Main *bmain = CTX_data_main(C);
649         Scene *scene = CTX_data_scene(C);
650         ViewLayer *view_layer = CTX_data_view_layer(C);
651
652         if (!ED_scene_view_layer_delete(bmain, scene, view_layer, NULL)) {
653                 return OPERATOR_CANCELLED;
654         }
655
656         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
657
658         return OPERATOR_FINISHED;
659 }
660
661 void SCENE_OT_view_layer_remove(wmOperatorType *ot)
662 {
663         /* identifiers */
664         ot->name = "Remove View Layer";
665         ot->idname = "SCENE_OT_view_layer_remove";
666         ot->description = "Remove the selected view layer";
667
668         /* api callbacks */
669         ot->exec = view_layer_remove_exec;
670
671         /* flags */
672         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
673 }
674
675 /********************** render view operators *********************/
676
677 static int render_view_remove_poll(bContext *C)
678 {
679         Scene *scene = CTX_data_scene(C);
680
681         /* don't allow user to remove "left" and "right" views */
682         return scene->r.actview > 1;
683 }
684
685 static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op))
686 {
687         Scene *scene = CTX_data_scene(C);
688
689         BKE_scene_add_render_view(scene, NULL);
690         scene->r.actview = BLI_listbase_count(&scene->r.views) - 1;
691
692         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
693
694         return OPERATOR_FINISHED;
695 }
696
697 void SCENE_OT_render_view_add(wmOperatorType *ot)
698 {
699         /* identifiers */
700         ot->name = "Add Render View";
701         ot->idname = "SCENE_OT_render_view_add";
702         ot->description = "Add a render view";
703
704         /* api callbacks */
705         ot->exec = render_view_add_exec;
706
707         /* flags */
708         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
709 }
710
711 static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op))
712 {
713         Scene *scene = CTX_data_scene(C);
714         SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview);
715
716         if (!BKE_scene_remove_render_view(scene, rv))
717                 return OPERATOR_CANCELLED;
718
719         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
720
721         return OPERATOR_FINISHED;
722 }
723
724 void SCENE_OT_render_view_remove(wmOperatorType *ot)
725 {
726         /* identifiers */
727         ot->name = "Remove Render View";
728         ot->idname = "SCENE_OT_render_view_remove";
729         ot->description = "Remove the selected render view";
730
731         /* api callbacks */
732         ot->exec = render_view_remove_exec;
733         ot->poll = render_view_remove_poll;
734
735         /* flags */
736         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
737 }
738
739 #ifdef WITH_FREESTYLE
740
741 static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportList *reports)
742 {
743         if (!lineset) {
744                 BKE_report(reports, RPT_ERROR, "No active lineset and associated line style to manipulate the modifier");
745                 return false;
746         }
747         if (!lineset->linestyle) {
748                 BKE_report(reports, RPT_ERROR, "The active lineset does not have a line style (indicating data corruption)");
749                 return false;
750         }
751
752         return true;
753 }
754
755 static int freestyle_active_module_poll(bContext *C)
756 {
757         PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
758         FreestyleModuleConfig *module = ptr.data;
759
760         return module != NULL;
761 }
762
763 static int freestyle_module_add_exec(bContext *C, wmOperator *UNUSED(op))
764 {
765         Scene *scene = CTX_data_scene(C);
766         ViewLayer *view_layer = CTX_data_view_layer(C);
767
768         BKE_freestyle_module_add(&view_layer->freestyle_config);
769
770         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
771
772         return OPERATOR_FINISHED;
773 }
774
775 void SCENE_OT_freestyle_module_add(wmOperatorType *ot)
776 {
777         /* identifiers */
778         ot->name = "Add Freestyle Module";
779         ot->idname = "SCENE_OT_freestyle_module_add";
780         ot->description = "Add a style module into the list of modules";
781
782         /* api callbacks */
783         ot->exec = freestyle_module_add_exec;
784
785         /* flags */
786         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
787 }
788
789 static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op))
790 {
791         Scene *scene = CTX_data_scene(C);
792         ViewLayer *view_layer = CTX_data_view_layer(C);
793         PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
794         FreestyleModuleConfig *module = ptr.data;
795
796         BKE_freestyle_module_delete(&view_layer->freestyle_config, module);
797
798         DEG_id_tag_update(&scene->id, 0);
799         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
800
801         return OPERATOR_FINISHED;
802 }
803
804 void SCENE_OT_freestyle_module_remove(wmOperatorType *ot)
805 {
806         /* identifiers */
807         ot->name = "Remove Freestyle Module";
808         ot->idname = "SCENE_OT_freestyle_module_remove";
809         ot->description = "Remove the style module from the stack";
810
811         /* api callbacks */
812         ot->poll = freestyle_active_module_poll;
813         ot->exec = freestyle_module_remove_exec;
814
815         /* flags */
816         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
817 }
818
819 static int freestyle_module_move_exec(bContext *C, wmOperator *op)
820 {
821         Scene *scene = CTX_data_scene(C);
822         ViewLayer *view_layer = CTX_data_view_layer(C);
823         PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
824         FreestyleModuleConfig *module = ptr.data;
825         int dir = RNA_enum_get(op->ptr, "direction");
826
827         if (BKE_freestyle_module_move(&view_layer->freestyle_config, module, dir)) {
828                 DEG_id_tag_update(&scene->id, 0);
829                 WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
830         }
831
832         return OPERATOR_FINISHED;
833 }
834
835 void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
836 {
837         static const EnumPropertyItem direction_items[] = {
838                 {-1, "UP", 0, "Up", ""},
839                 {1, "DOWN", 0, "Down", ""},
840                 {0, NULL, 0, NULL, NULL}
841         };
842
843         /* identifiers */
844         ot->name = "Move Freestyle Module";
845         ot->idname = "SCENE_OT_freestyle_module_move";
846         ot->description = "Change the position of the style module within in the list of style modules";
847
848         /* api callbacks */
849         ot->poll = freestyle_active_module_poll;
850         ot->exec = freestyle_module_move_exec;
851
852         /* flags */
853         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
854
855         /* props */
856         RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction",
857                      "Direction to move the chosen style module towards");
858 }
859
860 static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
861 {
862         Main *bmain = CTX_data_main(C);
863         Scene *scene = CTX_data_scene(C);
864         ViewLayer *view_layer = CTX_data_view_layer(C);
865
866         BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, NULL);
867
868         DEG_id_tag_update(&scene->id, 0);
869         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
870
871         return OPERATOR_FINISHED;
872 }
873
874 void SCENE_OT_freestyle_lineset_add(wmOperatorType *ot)
875 {
876         /* identifiers */
877         ot->name = "Add Line Set";
878         ot->idname = "SCENE_OT_freestyle_lineset_add";
879         ot->description = "Add a line set into the list of line sets";
880
881         /* api callbacks */
882         ot->exec = freestyle_lineset_add_exec;
883
884         /* flags */
885         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
886 }
887
888 static int freestyle_active_lineset_poll(bContext *C)
889 {
890         ViewLayer *view_layer = CTX_data_view_layer(C);
891
892         if (!view_layer) {
893                 return false;
894         }
895
896         return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != NULL;
897 }
898
899 static int freestyle_lineset_copy_exec(bContext *C, wmOperator *UNUSED(op))
900 {
901         ViewLayer *view_layer = CTX_data_view_layer(C);
902
903         FRS_copy_active_lineset(&view_layer->freestyle_config);
904
905         return OPERATOR_FINISHED;
906 }
907
908 void SCENE_OT_freestyle_lineset_copy(wmOperatorType *ot)
909 {
910         /* identifiers */
911         ot->name = "Copy Line Set";
912         ot->idname = "SCENE_OT_freestyle_lineset_copy";
913         ot->description = "Copy the active line set to a buffer";
914
915         /* api callbacks */
916         ot->exec = freestyle_lineset_copy_exec;
917         ot->poll = freestyle_active_lineset_poll;
918
919         /* flags */
920         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
921 }
922
923 static int freestyle_lineset_paste_exec(bContext *C, wmOperator *UNUSED(op))
924 {
925         Scene *scene = CTX_data_scene(C);
926         ViewLayer *view_layer = CTX_data_view_layer(C);
927
928         FRS_paste_active_lineset(&view_layer->freestyle_config);
929
930         DEG_id_tag_update(&scene->id, 0);
931         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
932
933         return OPERATOR_FINISHED;
934 }
935
936 void SCENE_OT_freestyle_lineset_paste(wmOperatorType *ot)
937 {
938         /* identifiers */
939         ot->name = "Paste Line Set";
940         ot->idname = "SCENE_OT_freestyle_lineset_paste";
941         ot->description = "Paste the buffer content to the active line set";
942
943         /* api callbacks */
944         ot->exec = freestyle_lineset_paste_exec;
945         ot->poll = freestyle_active_lineset_poll;
946
947         /* flags */
948         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
949 }
950
951 static int freestyle_lineset_remove_exec(bContext *C, wmOperator *UNUSED(op))
952 {
953         Scene *scene = CTX_data_scene(C);
954         ViewLayer *view_layer = CTX_data_view_layer(C);
955
956         FRS_delete_active_lineset(&view_layer->freestyle_config);
957
958         DEG_id_tag_update(&scene->id, 0);
959         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
960
961         return OPERATOR_FINISHED;
962 }
963
964 void SCENE_OT_freestyle_lineset_remove(wmOperatorType *ot)
965 {
966         /* identifiers */
967         ot->name = "Remove Line Set";
968         ot->idname = "SCENE_OT_freestyle_lineset_remove";
969         ot->description = "Remove the active line set from the list of line sets";
970
971         /* api callbacks */
972         ot->exec = freestyle_lineset_remove_exec;
973         ot->poll = freestyle_active_lineset_poll;
974
975         /* flags */
976         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
977 }
978
979 static int freestyle_lineset_move_exec(bContext *C, wmOperator *op)
980 {
981         Scene *scene = CTX_data_scene(C);
982         ViewLayer *view_layer = CTX_data_view_layer(C);
983         int dir = RNA_enum_get(op->ptr, "direction");
984
985         if (FRS_move_active_lineset(&view_layer->freestyle_config, dir)) {
986                 DEG_id_tag_update(&scene->id, 0);
987                 WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
988         }
989
990         return OPERATOR_FINISHED;
991 }
992
993 void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
994 {
995         static const EnumPropertyItem direction_items[] = {
996                 {-1, "UP", 0, "Up", ""},
997                 {1, "DOWN", 0, "Down", ""},
998                 {0, NULL, 0, NULL, NULL}
999         };
1000
1001         /* identifiers */
1002         ot->name = "Move Line Set";
1003         ot->idname = "SCENE_OT_freestyle_lineset_move";
1004         ot->description = "Change the position of the active line set within the list of line sets";
1005
1006         /* api callbacks */
1007         ot->exec = freestyle_lineset_move_exec;
1008         ot->poll = freestyle_active_lineset_poll;
1009
1010         /* flags */
1011         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1012
1013         /* props */
1014         RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction",
1015                      "Direction to move the active line set towards");
1016 }
1017
1018 static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
1019 {
1020         Main *bmain = CTX_data_main(C);
1021         ViewLayer *view_layer = CTX_data_view_layer(C);
1022         FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
1023
1024         if (!lineset) {
1025                 BKE_report(op->reports, RPT_ERROR, "No active lineset to add a new line style to");
1026                 return OPERATOR_CANCELLED;
1027         }
1028         if (lineset->linestyle) {
1029                 id_us_min(&lineset->linestyle->id);
1030                 lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
1031         }
1032         else {
1033                 lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle");
1034         }
1035         DEG_id_tag_update(&lineset->linestyle->id, 0);
1036         WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
1037
1038         return OPERATOR_FINISHED;
1039 }
1040
1041 void SCENE_OT_freestyle_linestyle_new(wmOperatorType *ot)
1042 {
1043         /* identifiers */
1044         ot->name = "New Line Style";
1045         ot->idname = "SCENE_OT_freestyle_linestyle_new";
1046         ot->description = "Create a new line style, reusable by multiple line sets";
1047
1048         /* api callbacks */
1049         ot->exec = freestyle_linestyle_new_exec;
1050         ot->poll = freestyle_active_lineset_poll;
1051
1052         /* flags */
1053         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1054 }
1055
1056 static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op)
1057 {
1058         ViewLayer *view_layer = CTX_data_view_layer(C);
1059         FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
1060         int type = RNA_enum_get(op->ptr, "type");
1061
1062         if (!freestyle_linestyle_check_report(lineset, op->reports)) {
1063                 return OPERATOR_CANCELLED;
1064         }
1065
1066         if (BKE_linestyle_color_modifier_add(lineset->linestyle, NULL, type) == NULL) {
1067                 BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type");
1068                 return OPERATOR_CANCELLED;
1069         }
1070         DEG_id_tag_update(&lineset->linestyle->id, 0);
1071         WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
1072
1073         return OPERATOR_FINISHED;
1074 }
1075
1076 void SCENE_OT_freestyle_color_modifier_add(wmOperatorType *ot)
1077 {
1078         /* identifiers */
1079         ot->name = "Add Line Color Modifier";
1080         ot->idname = "SCENE_OT_freestyle_color_modifier_add";
1081         ot->description = "Add a line color modifier to the line style associated with the active lineset";
1082
1083         /* api callbacks */
1084         ot->invoke = WM_menu_invoke;
1085         ot->exec = freestyle_color_modifier_add_exec;
1086         ot->poll = freestyle_active_lineset_poll;
1087
1088         /* flags */
1089         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1090
1091         /* properties */
1092         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_linestyle_color_modifier_type_items, 0, "Type", "");
1093 }
1094
1095 static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op)
1096 {
1097         ViewLayer *view_layer = CTX_data_view_layer(C);
1098         FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
1099         int type = RNA_enum_get(op->ptr, "type");
1100
1101         if (!freestyle_linestyle_check_report(lineset, op->reports)) {
1102                 return OPERATOR_CANCELLED;
1103         }
1104
1105         if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, NULL, type) == NULL) {
1106                 BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type");
1107                 return OPERATOR_CANCELLED;
1108         }
1109         DEG_id_tag_update(&lineset->linestyle->id, 0);
1110         WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
1111
1112         return OPERATOR_FINISHED;
1113 }
1114
1115 void SCENE_OT_freestyle_alpha_modifier_add(wmOperatorType *ot)
1116 {
1117         /* identifiers */
1118         ot->name = "Add Alpha Transparency Modifier";
1119         ot->idname = "SCENE_OT_freestyle_alpha_modifier_add";
1120         ot->description = "Add an alpha transparency modifier to the line style associated with the active lineset";
1121
1122         /* api callbacks */
1123         ot->invoke = WM_menu_invoke;
1124         ot->exec = freestyle_alpha_modifier_add_exec;
1125         ot->poll = freestyle_active_lineset_poll;
1126
1127         /* flags */
1128         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1129
1130         /* properties */
1131         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_linestyle_alpha_modifier_type_items, 0, "Type", "");
1132 }
1133
1134 static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op)
1135 {
1136         ViewLayer *view_layer = CTX_data_view_layer(C);
1137         FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
1138         int type = RNA_enum_get(op->ptr, "type");
1139
1140         if (!freestyle_linestyle_check_report(lineset, op->reports)) {
1141                 return OPERATOR_CANCELLED;
1142         }
1143
1144         if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, NULL, type) == NULL) {
1145                 BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type");
1146                 return OPERATOR_CANCELLED;
1147         }
1148         DEG_id_tag_update(&lineset->linestyle->id, 0);
1149         WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
1150
1151         return OPERATOR_FINISHED;
1152 }
1153
1154 void SCENE_OT_freestyle_thickness_modifier_add(wmOperatorType *ot)
1155 {
1156         /* identifiers */
1157         ot->name = "Add Line Thickness Modifier";
1158         ot->idname = "SCENE_OT_freestyle_thickness_modifier_add";
1159         ot->description = "Add a line thickness modifier to the line style associated with the active lineset";
1160
1161         /* api callbacks */
1162         ot->invoke = WM_menu_invoke;
1163         ot->exec = freestyle_thickness_modifier_add_exec;
1164         ot->poll = freestyle_active_lineset_poll;
1165
1166         /* flags */
1167         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1168
1169         /* properties */
1170         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_linestyle_thickness_modifier_type_items, 0, "Type", "");
1171 }
1172
1173 static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op)
1174 {
1175         ViewLayer *view_layer = CTX_data_view_layer(C);
1176         FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
1177         int type = RNA_enum_get(op->ptr, "type");
1178
1179         if (!freestyle_linestyle_check_report(lineset, op->reports)) {
1180                 return OPERATOR_CANCELLED;
1181         }
1182
1183         if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, NULL, type) == NULL) {
1184                 BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type");
1185                 return OPERATOR_CANCELLED;
1186         }
1187         DEG_id_tag_update(&lineset->linestyle->id, 0);
1188         WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
1189
1190         return OPERATOR_FINISHED;
1191 }
1192
1193 void SCENE_OT_freestyle_geometry_modifier_add(wmOperatorType *ot)
1194 {
1195         /* identifiers */
1196         ot->name = "Add Stroke Geometry Modifier";
1197         ot->idname = "SCENE_OT_freestyle_geometry_modifier_add";
1198         ot->description = "Add a stroke geometry modifier to the line style associated with the active lineset";
1199
1200         /* api callbacks */
1201         ot->invoke = WM_menu_invoke;
1202         ot->exec = freestyle_geometry_modifier_add_exec;
1203         ot->poll = freestyle_active_lineset_poll;
1204
1205         /* flags */
1206         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1207
1208         /* properties */
1209         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_linestyle_geometry_modifier_type_items, 0, "Type", "");
1210 }
1211
1212 static int freestyle_get_modifier_type(PointerRNA *ptr)
1213 {
1214         if (RNA_struct_is_a(ptr->type, &RNA_LineStyleColorModifier))
1215                 return LS_MODIFIER_TYPE_COLOR;
1216         else if (RNA_struct_is_a(ptr->type, &RNA_LineStyleAlphaModifier))
1217                 return LS_MODIFIER_TYPE_ALPHA;
1218         else if (RNA_struct_is_a(ptr->type, &RNA_LineStyleThicknessModifier))
1219                 return LS_MODIFIER_TYPE_THICKNESS;
1220         else if (RNA_struct_is_a(ptr->type, &RNA_LineStyleGeometryModifier))
1221                 return LS_MODIFIER_TYPE_GEOMETRY;
1222         return -1;
1223 }
1224
1225 static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op)
1226 {
1227         ViewLayer *view_layer = CTX_data_view_layer(C);
1228         FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
1229         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
1230         LineStyleModifier *modifier = ptr.data;
1231
1232         if (!freestyle_linestyle_check_report(lineset, op->reports)) {
1233                 return OPERATOR_CANCELLED;
1234         }
1235
1236         switch (freestyle_get_modifier_type(&ptr)) {
1237                 case LS_MODIFIER_TYPE_COLOR:
1238                         BKE_linestyle_color_modifier_remove(lineset->linestyle, modifier);
1239                         break;
1240                 case LS_MODIFIER_TYPE_ALPHA:
1241                         BKE_linestyle_alpha_modifier_remove(lineset->linestyle, modifier);
1242                         break;
1243                 case LS_MODIFIER_TYPE_THICKNESS:
1244                         BKE_linestyle_thickness_modifier_remove(lineset->linestyle, modifier);
1245                         break;
1246                 case LS_MODIFIER_TYPE_GEOMETRY:
1247                         BKE_linestyle_geometry_modifier_remove(lineset->linestyle, modifier);
1248                         break;
1249                 default:
1250                         BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
1251                         return OPERATOR_CANCELLED;
1252         }
1253         DEG_id_tag_update(&lineset->linestyle->id, 0);
1254         WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
1255
1256         return OPERATOR_FINISHED;
1257 }
1258
1259 void SCENE_OT_freestyle_modifier_remove(wmOperatorType *ot)
1260 {
1261         /* identifiers */
1262         ot->name = "Remove Modifier";
1263         ot->idname = "SCENE_OT_freestyle_modifier_remove";
1264         ot->description = "Remove the modifier from the list of modifiers";
1265
1266         /* api callbacks */
1267         ot->exec = freestyle_modifier_remove_exec;
1268         ot->poll = freestyle_active_lineset_poll;
1269
1270         /* flags */
1271         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1272 }
1273
1274 static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op)
1275 {
1276         ViewLayer *view_layer = CTX_data_view_layer(C);
1277         FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
1278         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
1279         LineStyleModifier *modifier = ptr.data;
1280
1281         if (!freestyle_linestyle_check_report(lineset, op->reports)) {
1282                 return OPERATOR_CANCELLED;
1283         }
1284
1285         switch (freestyle_get_modifier_type(&ptr)) {
1286                 case LS_MODIFIER_TYPE_COLOR:
1287                         BKE_linestyle_color_modifier_copy(lineset->linestyle, modifier, 0);
1288                         break;
1289                 case LS_MODIFIER_TYPE_ALPHA:
1290                         BKE_linestyle_alpha_modifier_copy(lineset->linestyle, modifier, 0);
1291                         break;
1292                 case LS_MODIFIER_TYPE_THICKNESS:
1293                         BKE_linestyle_thickness_modifier_copy(lineset->linestyle, modifier, 0);
1294                         break;
1295                 case LS_MODIFIER_TYPE_GEOMETRY:
1296                         BKE_linestyle_geometry_modifier_copy(lineset->linestyle, modifier, 0);
1297                         break;
1298                 default:
1299                         BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
1300                         return OPERATOR_CANCELLED;
1301         }
1302         DEG_id_tag_update(&lineset->linestyle->id, 0);
1303         WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
1304
1305         return OPERATOR_FINISHED;
1306 }
1307
1308 void SCENE_OT_freestyle_modifier_copy(wmOperatorType *ot)
1309 {
1310         /* identifiers */
1311         ot->name = "Copy Modifier";
1312         ot->idname = "SCENE_OT_freestyle_modifier_copy";
1313         ot->description = "Duplicate the modifier within the list of modifiers";
1314
1315         /* api callbacks */
1316         ot->exec = freestyle_modifier_copy_exec;
1317         ot->poll = freestyle_active_lineset_poll;
1318
1319         /* flags */
1320         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1321 }
1322
1323 static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
1324 {
1325         ViewLayer *view_layer = CTX_data_view_layer(C);
1326         FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
1327         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
1328         LineStyleModifier *modifier = ptr.data;
1329         int dir = RNA_enum_get(op->ptr, "direction");
1330         bool changed = false;
1331
1332         if (!freestyle_linestyle_check_report(lineset, op->reports)) {
1333                 return OPERATOR_CANCELLED;
1334         }
1335
1336         switch (freestyle_get_modifier_type(&ptr)) {
1337                 case LS_MODIFIER_TYPE_COLOR:
1338                         changed = BKE_linestyle_color_modifier_move(lineset->linestyle, modifier, dir);
1339                         break;
1340                 case LS_MODIFIER_TYPE_ALPHA:
1341                         changed = BKE_linestyle_alpha_modifier_move(lineset->linestyle, modifier, dir);
1342                         break;
1343                 case LS_MODIFIER_TYPE_THICKNESS:
1344                         changed = BKE_linestyle_thickness_modifier_move(lineset->linestyle, modifier, dir);
1345                         break;
1346                 case LS_MODIFIER_TYPE_GEOMETRY:
1347                         changed = BKE_linestyle_geometry_modifier_move(lineset->linestyle, modifier, dir);
1348                         break;
1349                 default:
1350                         BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
1351                         return OPERATOR_CANCELLED;
1352         }
1353
1354         if (changed) {
1355                 DEG_id_tag_update(&lineset->linestyle->id, 0);
1356                 WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
1357         }
1358
1359         return OPERATOR_FINISHED;
1360 }
1361
1362 void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
1363 {
1364         static const EnumPropertyItem direction_items[] = {
1365                 {-1, "UP", 0, "Up", ""},
1366                 {1, "DOWN", 0, "Down", ""},
1367                 {0, NULL, 0, NULL, NULL}
1368         };
1369
1370         /* identifiers */
1371         ot->name = "Move Modifier";
1372         ot->idname = "SCENE_OT_freestyle_modifier_move";
1373         ot->description = "Move the modifier within the list of modifiers";
1374
1375         /* api callbacks */
1376         ot->exec = freestyle_modifier_move_exec;
1377         ot->poll = freestyle_active_lineset_poll;
1378
1379         /* flags */
1380         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1381
1382         /* props */
1383         RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction",
1384                      "Direction to move the chosen modifier towards");
1385 }
1386
1387 static int freestyle_stroke_material_create_exec(bContext *C, wmOperator *op)
1388 {
1389         Main *bmain = CTX_data_main(C);
1390         ViewLayer *view_layer = CTX_data_view_layer(C);
1391         FreestyleLineStyle *linestyle = BKE_linestyle_active_from_view_layer(view_layer);
1392
1393         if (!linestyle) {
1394                 BKE_report(op->reports, RPT_ERROR, "No active line style in the current scene");
1395                 return OPERATOR_CANCELLED;
1396         }
1397
1398         FRS_create_stroke_material(bmain, linestyle);
1399
1400         return OPERATOR_FINISHED;
1401 }
1402
1403 void SCENE_OT_freestyle_stroke_material_create(wmOperatorType *ot)
1404 {
1405         /* identifiers */
1406         ot->name = "Create Freestyle Stroke Material";
1407         ot->idname = "SCENE_OT_freestyle_stroke_material_create";
1408         ot->description = "Create Freestyle stroke material for testing";
1409
1410         /* api callbacks */
1411         ot->exec = freestyle_stroke_material_create_exec;
1412
1413         /* flags */
1414         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1415 }
1416
1417 #endif /* WITH_FREESTYLE */
1418
1419 static int texture_slot_move_exec(bContext *C, wmOperator *op)
1420 {
1421         ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).id.data;
1422
1423         if (id) {
1424                 MTex **mtex_ar, *mtexswap;
1425                 short act;
1426                 int type = RNA_enum_get(op->ptr, "type");
1427                 struct AnimData *adt = BKE_animdata_from_id(id);
1428
1429                 give_active_mtex(id, &mtex_ar, &act);
1430
1431                 if (type == -1) { /* Up */
1432                         if (act > 0) {
1433                                 mtexswap = mtex_ar[act];
1434                                 mtex_ar[act] = mtex_ar[act - 1];
1435                                 mtex_ar[act - 1] = mtexswap;
1436
1437                                 BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act - 1, -1, 0);
1438                                 BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act - 1, 0);
1439                                 BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
1440
1441                                 set_active_mtex(id, act - 1);
1442                         }
1443                 }
1444                 else { /* Down */
1445                         if (act < MAX_MTEX - 1) {
1446                                 mtexswap = mtex_ar[act];
1447                                 mtex_ar[act] = mtex_ar[act + 1];
1448                                 mtex_ar[act + 1] = mtexswap;
1449
1450                                 BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act + 1, -1, 0);
1451                                 BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act + 1, 0);
1452                                 BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
1453
1454                                 set_active_mtex(id, act + 1);
1455                         }
1456                 }
1457
1458                 DEG_id_tag_update(id, 0);
1459                 WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C));
1460         }
1461
1462         return OPERATOR_FINISHED;
1463 }
1464
1465 void TEXTURE_OT_slot_move(wmOperatorType *ot)
1466 {
1467         static const EnumPropertyItem slot_move[] = {
1468                 {-1, "UP", 0, "Up", ""},
1469                 {1, "DOWN", 0, "Down", ""},
1470                 {0, NULL, 0, NULL, NULL}
1471         };
1472
1473         /* identifiers */
1474         ot->name = "Move Texture Slot";
1475         ot->idname = "TEXTURE_OT_slot_move";
1476         ot->description = "Move texture slots up and down";
1477
1478         /* api callbacks */
1479         ot->exec = texture_slot_move_exec;
1480
1481         /* flags */
1482         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1483
1484         RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
1485 }
1486
1487
1488
1489 /********************** material operators *********************/
1490
1491 /* material copy/paste */
1492 static int copy_material_exec(bContext *C, wmOperator *UNUSED(op))
1493 {
1494         Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
1495
1496         if (ma == NULL)
1497                 return OPERATOR_CANCELLED;
1498
1499         copy_matcopybuf(CTX_data_main(C), ma);
1500
1501         return OPERATOR_FINISHED;
1502 }
1503
1504 void MATERIAL_OT_copy(wmOperatorType *ot)
1505 {
1506         /* identifiers */
1507         ot->name = "Copy Material";
1508         ot->idname = "MATERIAL_OT_copy";
1509         ot->description = "Copy the material settings and nodes";
1510
1511         /* api callbacks */
1512         ot->exec = copy_material_exec;
1513
1514         /* flags */
1515         ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL; /* no undo needed since no changes are made to the material */
1516 }
1517
1518 static int paste_material_exec(bContext *C, wmOperator *UNUSED(op))
1519 {
1520         Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
1521
1522         if (ma == NULL)
1523                 return OPERATOR_CANCELLED;
1524
1525         paste_matcopybuf(CTX_data_main(C), ma);
1526
1527         WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
1528
1529         return OPERATOR_FINISHED;
1530 }
1531
1532 void MATERIAL_OT_paste(wmOperatorType *ot)
1533 {
1534         /* identifiers */
1535         ot->name = "Paste Material";
1536         ot->idname = "MATERIAL_OT_paste";
1537         ot->description = "Paste the material settings and nodes";
1538
1539         /* api callbacks */
1540         ot->exec = paste_material_exec;
1541
1542         /* flags */
1543         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1544 }
1545
1546
1547 static short mtexcopied = 0; /* must be reset on file load */
1548 static MTex mtexcopybuf;
1549
1550 void ED_render_clear_mtex_copybuf(void)
1551 {   /* use for file reload */
1552         mtexcopied = 0;
1553 }
1554
1555 static void copy_mtex_copybuf(ID *id)
1556 {
1557         MTex **mtex = NULL;
1558
1559         switch (GS(id->name)) {
1560                 case ID_PA:
1561                         mtex = &(((ParticleSettings *)id)->mtex[(int)((ParticleSettings *)id)->texact]);
1562                         break;
1563                 case ID_LS:
1564                         mtex = &(((FreestyleLineStyle *)id)->mtex[(int)((FreestyleLineStyle *)id)->texact]);
1565                         break;
1566                 default:
1567                         break;
1568         }
1569
1570         if (mtex && *mtex) {
1571                 memcpy(&mtexcopybuf, *mtex, sizeof(MTex));
1572                 mtexcopied = 1;
1573         }
1574         else {
1575                 mtexcopied = 0;
1576         }
1577 }
1578
1579 static void paste_mtex_copybuf(ID *id)
1580 {
1581         MTex **mtex = NULL;
1582
1583         if (mtexcopied == 0 || mtexcopybuf.tex == NULL)
1584                 return;
1585
1586         switch (GS(id->name)) {
1587                 case ID_PA:
1588                         mtex = &(((ParticleSettings *)id)->mtex[(int)((ParticleSettings *)id)->texact]);
1589                         break;
1590                 case ID_LS:
1591                         mtex = &(((FreestyleLineStyle *)id)->mtex[(int)((FreestyleLineStyle *)id)->texact]);
1592                         break;
1593                 default:
1594                         BLI_assert(!"invalid id type");
1595                         return;
1596         }
1597
1598         if (mtex) {
1599                 if (*mtex == NULL) {
1600                         *mtex = MEM_mallocN(sizeof(MTex), "mtex copy");
1601                 }
1602                 else if ((*mtex)->tex) {
1603                         id_us_min(&(*mtex)->tex->id);
1604                 }
1605
1606                 memcpy(*mtex, &mtexcopybuf, sizeof(MTex));
1607
1608                 id_us_plus((ID *)mtexcopybuf.tex);
1609         }
1610 }
1611
1612
1613 static int copy_mtex_exec(bContext *C, wmOperator *UNUSED(op))
1614 {
1615         ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).id.data;
1616
1617         if (id == NULL) {
1618                 /* copying empty slot */
1619                 ED_render_clear_mtex_copybuf();
1620                 return OPERATOR_CANCELLED;
1621         }
1622
1623         copy_mtex_copybuf(id);
1624
1625         return OPERATOR_FINISHED;
1626 }
1627
1628 static int copy_mtex_poll(bContext *C)
1629 {
1630         ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).id.data;
1631
1632         return (id != NULL);
1633 }
1634
1635 void TEXTURE_OT_slot_copy(wmOperatorType *ot)
1636 {
1637         /* identifiers */
1638         ot->name = "Copy Texture Slot Settings";
1639         ot->idname = "TEXTURE_OT_slot_copy";
1640         ot->description = "Copy the material texture settings and nodes";
1641
1642         /* api callbacks */
1643         ot->exec = copy_mtex_exec;
1644         ot->poll = copy_mtex_poll;
1645
1646         /* flags */
1647         ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL; /* no undo needed since no changes are made to the mtex */
1648 }
1649
1650 static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
1651 {
1652         ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).id.data;
1653
1654         if (id == NULL) {
1655                 Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
1656                 Lamp *la = CTX_data_pointer_get_type(C, "lamp", &RNA_Lamp).data;
1657                 World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
1658                 ParticleSystem *psys = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
1659                 FreestyleLineStyle *linestyle = CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data;
1660
1661                 if (ma)
1662                         id = &ma->id;
1663                 else if (la)
1664                         id = &la->id;
1665                 else if (wo)
1666                         id = &wo->id;
1667                 else if (psys)
1668                         id = &psys->part->id;
1669                 else if (linestyle)
1670                         id = &linestyle->id;
1671
1672                 if (id == NULL)
1673                         return OPERATOR_CANCELLED;
1674         }
1675
1676         paste_mtex_copybuf(id);
1677
1678         WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, NULL);
1679
1680         return OPERATOR_FINISHED;
1681 }
1682
1683 void TEXTURE_OT_slot_paste(wmOperatorType *ot)
1684 {
1685         /* identifiers */
1686         ot->name = "Paste Texture Slot Settings";
1687         ot->idname = "TEXTURE_OT_slot_paste";
1688         ot->description = "Copy the texture settings and nodes";
1689
1690         /* api callbacks */
1691         ot->exec = paste_mtex_exec;
1692
1693         /* flags */
1694         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
1695 }
1696