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