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