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