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