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