svn merge -r41422:41431 ^/trunk/blender
[blender.git] / source / blender / editors / render / render_shading.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16  *
17  * The Original Code is Copyright (C) 2009 Blender Foundation.
18  * All rights reserved.
19  *
20  * Contributor(s): Blender Foundation
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/render/render_shading.c
26  *  \ingroup edrend
27  */
28
29
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_curve_types.h"
36 #include "DNA_lamp_types.h"
37 #include "DNA_material_types.h"
38 #include "DNA_node_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_particle_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_space_types.h"
43 #include "DNA_world_types.h"
44
45 #include "BLI_blenlib.h"
46 #include "BLI_math.h"
47 #include "BLI_editVert.h"
48 #include "BLI_utildefines.h"
49
50 #include "BKE_animsys.h"
51 #include "BKE_context.h"
52 #include "BKE_curve.h"
53 #include "BKE_depsgraph.h"
54 #include "BKE_font.h"
55 #include "BKE_global.h"
56 #include "BKE_icons.h"
57 #include "BKE_image.h"
58 #include "BKE_library.h"
59 #include "BKE_main.h"
60 #include "BKE_material.h"
61 #include "BKE_node.h"
62 #include "BKE_report.h"
63 #include "BKE_scene.h"
64 #include "BKE_texture.h"
65 #include "BKE_world.h"
66 #include "BKE_tessmesh.h"
67
68 #include "IMB_imbuf.h"
69 #include "IMB_imbuf_types.h"
70
71 #include "GPU_material.h"
72
73 #include "RNA_access.h"
74
75 #include "WM_api.h"
76 #include "WM_types.h"
77
78 #include "ED_curve.h"
79 #include "ED_mesh.h"
80 #include "ED_render.h"
81 #include "ED_screen.h"
82
83 #include "RNA_define.h"
84
85 #include "UI_interface.h"
86
87 #include "RE_pipeline.h"
88
89 #include "render_intern.h"      // own include
90
91 /********************** material slot operators *********************/
92
93 static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
94 {
95         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
96
97         if(!ob)
98                 return OPERATOR_CANCELLED;
99
100         object_add_material_slot(ob);
101         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
102         WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, ob);
103         
104         return OPERATOR_FINISHED;
105 }
106
107 void OBJECT_OT_material_slot_add(wmOperatorType *ot)
108 {
109         /* identifiers */
110         ot->name= "Add Material Slot";
111         ot->idname= "OBJECT_OT_material_slot_add";
112         ot->description="Add a new material slot";
113         
114         /* api callbacks */
115         ot->exec= material_slot_add_exec;
116         ot->poll= ED_operator_object_active_editable;
117
118         /* flags */
119         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
120 }
121
122 static int material_slot_remove_exec(bContext *C, wmOperator *op)
123 {
124         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
125
126         if(!ob)
127                 return OPERATOR_CANCELLED;
128
129         /* Removing material slots in edit mode screws things up, see bug #21822.*/
130         if(ob == CTX_data_edit_object(C)) {
131                 BKE_report(op->reports, RPT_ERROR, "Unable to remove material slot in edit mode");
132                 return OPERATOR_CANCELLED;
133         }
134
135         object_remove_material_slot(ob);
136         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
137         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
138         WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, ob);
139         
140         return OPERATOR_FINISHED;
141 }
142
143 void OBJECT_OT_material_slot_remove(wmOperatorType *ot)
144 {
145         /* identifiers */
146         ot->name= "Remove Material Slot";
147         ot->idname= "OBJECT_OT_material_slot_remove";
148         ot->description="Remove the selected material slot";
149         
150         /* api callbacks */
151         ot->exec= material_slot_remove_exec;
152         ot->poll= ED_operator_object_active_editable;
153
154         /* flags */
155         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
156 }
157
158 static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
159 {
160         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
161
162         if(!ob)
163                 return OPERATOR_CANCELLED;
164
165         if(ob && ob->actcol>0) {
166                 if(ob->type == OB_MESH) {
167                         BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
168                         BMFace *efa;
169                         BMIter iter;
170
171                         if(em) {
172                                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
173                                         if(BM_TestHFlag(efa, BM_SELECT))
174                                                 efa->mat_nr= ob->actcol-1;
175                                 }
176                         }
177                 }
178                 else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
179                         Nurb *nu;
180                         ListBase *nurbs= curve_editnurbs((Curve*)ob->data);
181
182                         if(nurbs) {
183                                 for(nu= nurbs->first; nu; nu= nu->next)
184                                         if(isNurbsel(nu))
185                                                 nu->mat_nr= nu->charidx= ob->actcol-1;
186                         }
187                 }
188                 else if(ob->type == OB_FONT) {
189                         EditFont *ef= ((Curve*)ob->data)->editfont;
190                         int i, selstart, selend;
191
192                         if(ef && BKE_font_getselection(ob, &selstart, &selend)) {
193                                 for(i=selstart; i<=selend; i++)
194                                         ef->textbufinfo[i].mat_nr = ob->actcol;
195                         }
196                 }
197         }
198
199         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
200         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
201         
202         return OPERATOR_FINISHED;
203 }
204
205 void OBJECT_OT_material_slot_assign(wmOperatorType *ot)
206 {
207         /* identifiers */
208         ot->name= "Assign Material Slot";
209         ot->idname= "OBJECT_OT_material_slot_assign";
210         ot->description="Assign the material in the selected material slot to the selected vertices";
211         
212         /* api callbacks */
213         ot->exec= material_slot_assign_exec;
214         ot->poll= ED_operator_object_active_editable;
215
216         /* flags */
217         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
218 }
219
220 static int material_slot_de_select(bContext *C, int select)
221 {
222         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
223
224         if(!ob)
225                 return OPERATOR_CANCELLED;
226
227         if(ob->type == OB_MESH) {
228                 BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
229
230                 if(em) {
231                         EDBM_deselect_by_material(em, ob->actcol-1, select);
232                 }
233         }
234         else if ELEM(ob->type, OB_CURVE, OB_SURF) {
235                 ListBase *nurbs= curve_editnurbs((Curve*)ob->data);
236                 Nurb *nu;
237                 BPoint *bp;
238                 BezTriple *bezt;
239                 int a;
240
241                 if(nurbs) {
242                         for(nu= nurbs->first; nu; nu=nu->next) {
243                                 if(nu->mat_nr==ob->actcol-1) {
244                                         if(nu->bezt) {
245                                                 a= nu->pntsu;
246                                                 bezt= nu->bezt;
247                                                 while(a--) {
248                                                         if(bezt->hide==0) {
249                                                                 if(select) {
250                                                                         bezt->f1 |= SELECT;
251                                                                         bezt->f2 |= SELECT;
252                                                                         bezt->f3 |= SELECT;
253                                                                 }
254                                                                 else {
255                                                                         bezt->f1 &= ~SELECT;
256                                                                         bezt->f2 &= ~SELECT;
257                                                                         bezt->f3 &= ~SELECT;
258                                                                 }
259                                                         }
260                                                         bezt++;
261                                                 }
262                                         }
263                                         else if(nu->bp) {
264                                                 a= nu->pntsu*nu->pntsv;
265                                                 bp= nu->bp;
266                                                 while(a--) {
267                                                         if(bp->hide==0) {
268                                                                 if(select) bp->f1 |= SELECT;
269                                                                 else bp->f1 &= ~SELECT;
270                                                         }
271                                                         bp++;
272                                                 }
273                                         }
274                                 }
275                         }
276                 }
277         }
278
279         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
280
281         return OPERATOR_FINISHED;
282 }
283
284 static int material_slot_select_exec(bContext *C, wmOperator *UNUSED(op))
285 {
286         return material_slot_de_select(C, 1);
287 }
288
289 void OBJECT_OT_material_slot_select(wmOperatorType *ot)
290 {
291         /* identifiers */
292         ot->name= "Select Material Slot";
293         ot->idname= "OBJECT_OT_material_slot_select";
294         ot->description="Select vertices assigned to the selected material slot";
295         
296         /* api callbacks */
297         ot->exec= material_slot_select_exec;
298
299         /* flags */
300         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
301 }
302
303 static int material_slot_deselect_exec(bContext *C, wmOperator *UNUSED(op))
304 {
305         return material_slot_de_select(C, 0);
306 }
307
308 void OBJECT_OT_material_slot_deselect(wmOperatorType *ot)
309 {
310         /* identifiers */
311         ot->name= "Deselect Material Slot";
312         ot->idname= "OBJECT_OT_material_slot_deselect";
313         ot->description="Deselect vertices assigned to the selected material slot";
314         
315         /* api callbacks */
316         ot->exec= material_slot_deselect_exec;
317
318         /* flags */
319         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
320 }
321
322
323 static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
324 {
325         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
326         Material ***matar;
327
328         if(!ob || !(matar= give_matarar(ob)))
329                 return OPERATOR_CANCELLED;
330
331         CTX_DATA_BEGIN(C, Object*, ob_iter, selected_editable_objects) {
332                 if(ob != ob_iter && give_matarar(ob_iter)) {
333                         if (ob->data != ob_iter->data)
334                                 assign_matarar(ob_iter, matar, ob->totcol);
335                         
336                         if(ob_iter->totcol==ob->totcol) {
337                                 ob_iter->actcol= ob->actcol;
338                                 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob_iter);
339                         }
340                 }
341         }
342         CTX_DATA_END;
343
344         return OPERATOR_FINISHED;
345 }
346
347
348 void OBJECT_OT_material_slot_copy(wmOperatorType *ot)
349 {
350         /* identifiers */
351         ot->name= "Copy Material to Others";
352         ot->idname= "OBJECT_OT_material_slot_copy";
353         ot->description="Copies materials to other selected objects";
354
355         /* api callbacks */
356         ot->exec= material_slot_copy_exec;
357
358         /* flags */
359         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
360 }
361
362 /********************** new material operator *********************/
363
364 static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
365 {
366         Material *ma= CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
367         PointerRNA ptr, idptr;
368         PropertyRNA *prop;
369
370         /* add or copy material */
371         if(ma)
372                 ma= copy_material(ma);
373         else
374                 ma= add_material("Material");
375
376         /* hook into UI */
377         uiIDContextProperty(C, &ptr, &prop);
378
379         if(prop) {
380                 /* when creating new ID blocks, use is already 1, but RNA
381                  * pointer se also increases user, so this compensates it */
382                 ma->id.us--;
383
384                 RNA_id_pointer_create(&ma->id, &idptr);
385                 RNA_property_pointer_set(&ptr, prop, idptr);
386                 RNA_property_update(C, &ptr, prop);
387         }
388
389         WM_event_add_notifier(C, NC_MATERIAL|NA_ADDED, ma);
390         
391         return OPERATOR_FINISHED;
392 }
393
394 void MATERIAL_OT_new(wmOperatorType *ot)
395 {
396         /* identifiers */
397         ot->name= "New Material";
398         ot->idname= "MATERIAL_OT_new";
399         ot->description="Add a new material";
400         
401         /* api callbacks */
402         ot->exec= new_material_exec;
403
404         /* flags */
405         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
406 }
407
408 /********************** new texture operator *********************/
409
410 static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
411 {
412         Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
413         PointerRNA ptr, idptr;
414         PropertyRNA *prop;
415
416         /* add or copy texture */
417         if(tex)
418                 tex= copy_texture(tex);
419         else
420                 tex= add_texture("Texture");
421
422         /* hook into UI */
423         uiIDContextProperty(C, &ptr, &prop);
424
425         if(prop) {
426                 /* when creating new ID blocks, use is already 1, but RNA
427                  * pointer se also increases user, so this compensates it */
428                 tex->id.us--;
429
430                 RNA_id_pointer_create(&tex->id, &idptr);
431                 RNA_property_pointer_set(&ptr, prop, idptr);
432                 RNA_property_update(C, &ptr, prop);
433         }
434
435         WM_event_add_notifier(C, NC_TEXTURE|NA_ADDED, tex);
436         
437         return OPERATOR_FINISHED;
438 }
439
440 void TEXTURE_OT_new(wmOperatorType *ot)
441 {
442         /* identifiers */
443         ot->name= "New Texture";
444         ot->idname= "TEXTURE_OT_new";
445         ot->description="Add a new texture";
446         
447         /* api callbacks */
448         ot->exec= new_texture_exec;
449
450         /* flags */
451         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
452 }
453
454 /********************** new world operator *********************/
455
456 static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
457 {
458         World *wo= CTX_data_pointer_get_type(C, "world", &RNA_World).data;
459         PointerRNA ptr, idptr;
460         PropertyRNA *prop;
461
462         /* add or copy world */
463         if(wo)
464                 wo= copy_world(wo);
465         else
466                 wo= add_world("World");
467
468         /* hook into UI */
469         uiIDContextProperty(C, &ptr, &prop);
470
471         if(prop) {
472                 /* when creating new ID blocks, use is already 1, but RNA
473                  * pointer se also increases user, so this compensates it */
474                 wo->id.us--;
475
476                 RNA_id_pointer_create(&wo->id, &idptr);
477                 RNA_property_pointer_set(&ptr, prop, idptr);
478                 RNA_property_update(C, &ptr, prop);
479         }
480
481         WM_event_add_notifier(C, NC_WORLD|NA_ADDED, wo);
482         
483         return OPERATOR_FINISHED;
484 }
485
486 void WORLD_OT_new(wmOperatorType *ot)
487 {
488         /* identifiers */
489         ot->name= "New World";
490         ot->idname= "WORLD_OT_new";
491         ot->description= "Add a new world";
492         
493         /* api callbacks */
494         ot->exec= new_world_exec;
495
496         /* flags */
497         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
498 }
499
500 /********************** render layer operators *********************/
501
502 static int render_layer_add_exec(bContext *C, wmOperator *UNUSED(op))
503 {
504         Scene *scene= CTX_data_scene(C);
505
506         scene_add_render_layer(scene);
507         scene->r.actlay= BLI_countlist(&scene->r.layers) - 1;
508
509         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, scene);
510         
511         return OPERATOR_FINISHED;
512 }
513
514 void SCENE_OT_render_layer_add(wmOperatorType *ot)
515 {
516         /* identifiers */
517         ot->name= "Add Render Layer";
518         ot->idname= "SCENE_OT_render_layer_add";
519         ot->description="Add a render layer";
520         
521         /* api callbacks */
522         ot->exec= render_layer_add_exec;
523
524         /* flags */
525         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
526 }
527
528 static int render_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
529 {
530         Scene *scene = CTX_data_scene(C), *sce;
531         SceneRenderLayer *rl;
532         int act= scene->r.actlay;
533
534         if(BLI_countlist(&scene->r.layers) <= 1)
535                 return OPERATOR_CANCELLED;
536         
537         rl= BLI_findlink(&scene->r.layers, scene->r.actlay);
538         BLI_remlink(&scene->r.layers, rl);
539         MEM_freeN(rl);
540
541         scene->r.actlay= 0;
542
543         for(sce = CTX_data_main(C)->scene.first; sce; sce = sce->id.next) {
544                 if(sce->nodetree) {
545                         bNode *node;
546                         for(node = sce->nodetree->nodes.first; node; node = node->next) {
547                                 if(node->type==CMP_NODE_R_LAYERS && (Scene*)node->id==scene) {
548                                         if(node->custom1==act)
549                                                 node->custom1= 0;
550                                         else if(node->custom1>act)
551                                                 node->custom1--;
552                                 }
553                         }
554                 }
555         }
556
557         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, scene);
558         
559         return OPERATOR_FINISHED;
560 }
561
562 void SCENE_OT_render_layer_remove(wmOperatorType *ot)
563 {
564         /* identifiers */
565         ot->name= "Remove Render Layer";
566         ot->idname= "SCENE_OT_render_layer_remove";
567         ot->description="Remove the selected render layer";
568         
569         /* api callbacks */
570         ot->exec= render_layer_remove_exec;
571
572         /* flags */
573         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
574 }
575
576 static int texture_slot_move(bContext *C, wmOperator *op)
577 {
578         ID *id= CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).id.data;
579
580         if(id) {
581                 MTex **mtex_ar, *mtexswap;
582                 short act;
583                 int type= RNA_enum_get(op->ptr, "type");
584                 struct AnimData *adt= BKE_animdata_from_id(id);
585
586                 give_active_mtex(id, &mtex_ar, &act);
587
588                 if(type == -1) { /* Up */
589                         if(act > 0) {
590                                 mtexswap = mtex_ar[act];
591                                 mtex_ar[act] = mtex_ar[act-1];
592                                 mtex_ar[act-1] = mtexswap;
593                                 
594                                 BKE_animdata_fix_paths_rename(id, adt, "texture_slots", NULL, NULL, act-1, -1, 0);
595                                 BKE_animdata_fix_paths_rename(id, adt, "texture_slots", NULL, NULL, act, act-1, 0);
596                                 BKE_animdata_fix_paths_rename(id, adt, "texture_slots", NULL, NULL, -1, act, 0);
597
598                                 if(GS(id->name)==ID_MA) {
599                                         Material *ma= (Material *)id;
600                                         int mtexuse = ma->septex & (1<<act);
601                                         ma->septex &= ~(1<<act);
602                                         ma->septex |= (ma->septex & (1<<(act-1))) << 1;
603                                         ma->septex &= ~(1<<(act-1));
604                                         ma->septex |= mtexuse >> 1;
605                                 }
606                                 
607                                 set_active_mtex(id, act-1);
608                         }
609                 }
610                 else { /* Down */
611                         if(act < MAX_MTEX-1) {
612                                 mtexswap = mtex_ar[act];
613                                 mtex_ar[act] = mtex_ar[act+1];
614                                 mtex_ar[act+1] = mtexswap;
615                                 
616                                 BKE_animdata_fix_paths_rename(id, adt, "texture_slots", NULL, NULL, act+1, -1, 0);
617                                 BKE_animdata_fix_paths_rename(id, adt, "texture_slots", NULL, NULL, act, act+1, 0);
618                                 BKE_animdata_fix_paths_rename(id, adt, "texture_slots", NULL, NULL, -1, act, 0);
619
620                                 if(GS(id->name)==ID_MA) {
621                                         Material *ma= (Material *)id;
622                                         int mtexuse = ma->septex & (1<<act);
623                                         ma->septex &= ~(1<<act);
624                                         ma->septex |= (ma->septex & (1<<(act+1))) >> 1;
625                                         ma->septex &= ~(1<<(act+1));
626                                         ma->septex |= mtexuse << 1;
627                                 }
628                                 
629                                 set_active_mtex(id, act+1);
630                         }
631                 }
632
633                 DAG_id_tag_update(id, 0);
634                 WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C));
635         }
636
637         return OPERATOR_FINISHED;
638 }
639
640 void TEXTURE_OT_slot_move(wmOperatorType *ot)
641 {
642         static EnumPropertyItem slot_move[] = {
643                 {-1, "UP", 0, "Up", ""},
644                 {1, "DOWN", 0, "Down", ""},
645                 {0, NULL, 0, NULL, NULL}
646         };
647
648         /* identifiers */
649         ot->name= "Move Texture Slot";
650         ot->idname= "TEXTURE_OT_slot_move";
651         ot->description="Move texture slots up and down";
652
653         /* api callbacks */
654         ot->exec= texture_slot_move;
655
656         /* flags */
657         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
658
659         RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
660 }
661
662
663
664 /********************** environment map operators *********************/
665
666 static int save_envmap(wmOperator *op, Scene *scene, EnvMap *env, char *path, int imtype)
667 {
668         float layout[12];
669         if ( RNA_struct_find_property(op->ptr, "layout") )
670                 RNA_float_get_array(op->ptr, "layout",layout);
671         else
672                 memcpy(layout, default_envmap_layout, sizeof(layout));
673
674         if (RE_WriteEnvmapResult(op->reports, scene, env, path, imtype, layout)) {
675                 return OPERATOR_FINISHED;
676         }
677         else {
678                 return OPERATOR_CANCELLED;
679         }
680
681 }
682
683 static int envmap_save_exec(bContext *C, wmOperator *op)
684 {
685         Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
686         Scene *scene = CTX_data_scene(C);
687         //int imtype = RNA_enum_get(op->ptr, "file_type");
688         int imtype = scene->r.imtype;
689         char path[FILE_MAX];
690         
691         RNA_string_get(op->ptr, "filepath", path);
692         
693         if(scene->r.scemode & R_EXTENSION)  {
694                 BKE_add_image_extension(path, imtype);
695         }
696         
697         WM_cursor_wait(1);
698         
699         save_envmap(op, scene, tex->env, path, imtype);
700         
701         WM_cursor_wait(0);
702         
703         WM_event_add_notifier(C, NC_TEXTURE, tex);
704         
705         return OPERATOR_FINISHED;
706 }
707
708 static int envmap_save_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
709 {
710         //Scene *scene= CTX_data_scene(C);
711         
712         if(RNA_property_is_set(op->ptr, "filepath"))
713                 return envmap_save_exec(C, op);
714
715         //RNA_enum_set(op->ptr, "file_type", scene->r.imtype);
716         RNA_string_set(op->ptr, "filepath", G.main->name);
717         WM_event_add_fileselect(C, op);
718         
719         return OPERATOR_RUNNING_MODAL;
720 }
721
722 static int envmap_save_poll(bContext *C)
723 {
724         Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
725
726         if (!tex) 
727                 return 0;
728         if (!tex->env || !tex->env->ok)
729                 return 0;
730         if (tex->env->cube[1]==NULL)
731                 return 0;
732         
733         return 1;
734 }
735
736 void TEXTURE_OT_envmap_save(wmOperatorType *ot)
737 {
738         PropertyRNA *prop;
739         /* identifiers */
740         ot->name= "Save Environment Map";
741         ot->idname= "TEXTURE_OT_envmap_save";
742         ot->description="Save the current generated Environment map to an image file";
743         
744         /* api callbacks */
745         ot->exec= envmap_save_exec;
746         ot->invoke= envmap_save_invoke;
747         ot->poll= envmap_save_poll;
748         
749         /* flags */
750         ot->flag= OPTYPE_REGISTER; /* no undo since this doesnt modify the env-map */
751         
752         /* properties */
753         prop= RNA_def_float_array(ot->srna, "layout", 12, default_envmap_layout, 0.0f, 0.0f, "File layout", "Flat array describing the X,Y position of each cube face in the output image, where 1 is the size of a face - order is [+Z -Z +Y -X -Y +X] (use -1 to skip a face)", 0.0f, 0.0f);
754         RNA_def_property_flag(prop, PROP_HIDDEN);
755
756         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH);
757 }
758
759 static int envmap_clear_exec(bContext *C, wmOperator *UNUSED(op))
760 {
761         Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
762         
763         BKE_free_envmapdata(tex->env);
764         
765         WM_event_add_notifier(C, NC_TEXTURE|NA_EDITED, tex);
766         
767         return OPERATOR_FINISHED;
768 }
769
770 static int envmap_clear_poll(bContext *C)
771 {
772         Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
773         
774         if (!tex) 
775                 return 0;
776         if (!tex->env || !tex->env->ok)
777                 return 0;
778         if (tex->env->cube[1]==NULL)
779                 return 0;
780         
781         return 1;
782 }
783
784 void TEXTURE_OT_envmap_clear(wmOperatorType *ot)
785 {
786         /* identifiers */
787         ot->name= "Clear Environment Map";
788         ot->idname= "TEXTURE_OT_envmap_clear";
789         ot->description="Discard the environment map and free it from memory";
790         
791         /* api callbacks */
792         ot->exec= envmap_clear_exec;
793         ot->poll= envmap_clear_poll;
794         
795         /* flags */
796         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
797 }
798
799 static int envmap_clear_all_exec(bContext *C, wmOperator *UNUSED(op))
800 {
801         Main *bmain = CTX_data_main(C);
802         Tex *tex;
803         
804         for (tex=bmain->tex.first; tex; tex=tex->id.next)
805                 if (tex->env)
806                         BKE_free_envmapdata(tex->env);
807         
808         WM_event_add_notifier(C, NC_TEXTURE|NA_EDITED, tex);
809         
810         return OPERATOR_FINISHED;
811 }
812
813 void TEXTURE_OT_envmap_clear_all(wmOperatorType *ot)
814 {
815         /* identifiers */
816         ot->name= "Clear All Environment Maps";
817         ot->idname= "TEXTURE_OT_envmap_clear_all";
818         ot->description="Discard all environment maps in the .blend file and free them from memory";
819         
820         /* api callbacks */
821         ot->exec= envmap_clear_all_exec;
822         ot->poll= envmap_clear_poll;
823         
824         /* flags */
825         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
826 }
827
828 /********************** material operators *********************/
829
830 /* material copy/paste */
831 static int copy_material_exec(bContext *C, wmOperator *UNUSED(op))
832 {
833         Material *ma= CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
834
835         if(ma==NULL)
836                 return OPERATOR_CANCELLED;
837
838         copy_matcopybuf(ma);
839
840         return OPERATOR_FINISHED;
841 }
842
843 void MATERIAL_OT_copy(wmOperatorType *ot)
844 {
845         /* identifiers */
846         ot->name= "Copy Material";
847         ot->idname= "MATERIAL_OT_copy";
848         ot->description="Copy the material settings and nodes";
849
850         /* api callbacks */
851         ot->exec= copy_material_exec;
852
853         /* flags */
854         ot->flag= OPTYPE_REGISTER; /* no undo needed since no changes are made to the material */
855 }
856
857 static int paste_material_exec(bContext *C, wmOperator *UNUSED(op))
858 {
859         Material *ma= CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
860
861         if(ma==NULL)
862                 return OPERATOR_CANCELLED;
863
864         paste_matcopybuf(ma);
865
866         WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING_DRAW, ma);
867
868         return OPERATOR_FINISHED;
869 }
870
871 void MATERIAL_OT_paste(wmOperatorType *ot)
872 {
873         /* identifiers */
874         ot->name= "Paste Material";
875         ot->idname= "MATERIAL_OT_paste";
876         ot->description="Paste the material settings and nodes";
877
878         /* api callbacks */
879         ot->exec= paste_material_exec;
880
881         /* flags */
882         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
883 }
884
885
886 static short mtexcopied=0; /* must be reset on file load */
887 static MTex mtexcopybuf;
888
889 void ED_render_clear_mtex_copybuf(void)
890 {       /* use for file reload */
891         mtexcopied= 0;
892 }
893
894 static void copy_mtex_copybuf(ID *id)
895 {
896         MTex **mtex= NULL;
897         
898         switch(GS(id->name)) {
899                 case ID_MA:
900                         mtex= &(((Material *)id)->mtex[(int)((Material *)id)->texact]);
901                         break;
902                 case ID_LA:
903                         mtex= &(((Lamp *)id)->mtex[(int)((Lamp *)id)->texact]);
904                         // la->mtex[(int)la->texact] // TODO
905                         break;
906                 case ID_WO:
907                         mtex= &(((World *)id)->mtex[(int)((World *)id)->texact]);
908                         // mtex= wrld->mtex[(int)wrld->texact]; // TODO
909                         break;
910                 case ID_PA:
911                         mtex= &(((ParticleSettings *)id)->mtex[(int)((ParticleSettings *)id)->texact]);
912                         break;
913         }
914         
915         if(mtex && *mtex) {
916                 memcpy(&mtexcopybuf, *mtex, sizeof(MTex));
917                 mtexcopied= 1;
918         }
919         else {
920                 mtexcopied= 0;
921         }
922 }
923
924 static void paste_mtex_copybuf(ID *id)
925 {
926         MTex **mtex= NULL;
927         
928         if(mtexcopied == 0 || mtexcopybuf.tex==NULL)
929                 return;
930         
931         switch(GS(id->name)) {
932                 case ID_MA:
933                         mtex= &(((Material *)id)->mtex[(int)((Material *)id)->texact]);
934                         break;
935                 case ID_LA:
936                         mtex= &(((Lamp *)id)->mtex[(int)((Lamp *)id)->texact]);
937                         // la->mtex[(int)la->texact] // TODO
938                         break;
939                 case ID_WO:
940                         mtex= &(((World *)id)->mtex[(int)((World *)id)->texact]);
941                         // mtex= wrld->mtex[(int)wrld->texact]; // TODO
942                         break;
943                 case ID_PA:
944                         mtex= &(((ParticleSettings *)id)->mtex[(int)((ParticleSettings *)id)->texact]);
945                         break;
946                 default:
947                         BLI_assert("invalid id type");
948                         return;
949         }
950         
951         if(mtex) {
952                 if(*mtex==NULL) {
953                         *mtex= MEM_mallocN(sizeof(MTex), "mtex copy");
954                 }
955                 else if((*mtex)->tex) {
956                         (*mtex)->tex->id.us--;
957                 }
958                 
959                 memcpy(*mtex, &mtexcopybuf, sizeof(MTex));
960                 
961                 id_us_plus((ID *)mtexcopybuf.tex);
962         }
963 }
964
965
966 static int copy_mtex_exec(bContext *C, wmOperator *UNUSED(op))
967 {
968         ID *id= CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).id.data;
969
970         if(id==NULL) {
971                 /* copying empty slot */
972                 ED_render_clear_mtex_copybuf();
973                 return OPERATOR_CANCELLED;
974         }
975
976         copy_mtex_copybuf(id);
977
978         return OPERATOR_FINISHED;
979 }
980
981 static int copy_mtex_poll(bContext *C)
982 {
983         ID *id= CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).id.data;
984         
985         return (id != NULL);
986 }
987
988 void TEXTURE_OT_slot_copy(wmOperatorType *ot)
989 {
990         /* identifiers */
991         ot->name= "Copy Texture Slot Settings";
992         ot->idname= "TEXTURE_OT_slot_copy";
993         ot->description="Copy the material texture settings and nodes";
994
995         /* api callbacks */
996         ot->exec= copy_mtex_exec;
997         ot->poll= copy_mtex_poll;
998         
999         /* flags */
1000         ot->flag= OPTYPE_REGISTER; /* no undo needed since no changes are made to the mtex */
1001 }
1002
1003 static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
1004 {
1005         ID *id= CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).id.data;
1006
1007         if(id==NULL) {
1008                 Material *ma= CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
1009                 Lamp *la= CTX_data_pointer_get_type(C, "lamp", &RNA_Lamp).data;
1010                 World *wo= CTX_data_pointer_get_type(C, "world", &RNA_World).data;
1011                 ParticleSystem *psys= CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
1012                 
1013                 if (ma)
1014                         id = &ma->id;
1015                 else if (la)
1016                         id = &la->id;
1017                 else if (wo)
1018                         id = &wo->id;
1019                 else if (psys)
1020                         id = &psys->part->id;
1021                 
1022                 if (id==NULL)
1023                         return OPERATOR_CANCELLED;
1024         }
1025
1026         paste_mtex_copybuf(id);
1027
1028         WM_event_add_notifier(C, NC_TEXTURE|ND_SHADING_DRAW, NULL);
1029
1030         return OPERATOR_FINISHED;
1031 }
1032
1033 void TEXTURE_OT_slot_paste(wmOperatorType *ot)
1034 {
1035         /* identifiers */
1036         ot->name= "Paste Texture Slot Settings";
1037         ot->idname= "TEXTURE_OT_slot_paste";
1038         ot->description="Copy the texture settings and nodes";
1039
1040         /* api callbacks */
1041         ot->exec= paste_mtex_exec;
1042
1043         /* flags */
1044         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1045 }
1046