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