56605ad097040acac6213516bcc527eaa062ff6d
[blender-staging.git] / source / blender / editors / render / render_shading.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_meshdata_types.h"
36 #include "DNA_node_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_texture_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_world_types.h"
41
42 #include "BKE_context.h"
43 #include "BKE_depsgraph.h"
44 #include "BKE_font.h"
45 #include "BKE_icons.h"
46 #include "BKE_library.h"
47 #include "BKE_main.h"
48 #include "BKE_material.h"
49 #include "BKE_node.h"
50 #include "BKE_scene.h"
51 #include "BKE_texture.h"
52 #include "BKE_utildefines.h"
53 #include "BKE_world.h"
54
55 #include "BLI_arithb.h"
56 #include "BLI_editVert.h"
57 #include "BLI_listbase.h"
58
59 #include "GPU_material.h"
60
61 #include "RNA_access.h"
62 #include "RNA_enum_types.h"
63
64 #include "WM_api.h"
65 #include "WM_types.h"
66
67 #include "ED_curve.h"
68 #include "ED_mesh.h"
69 #include "ED_render.h"
70
71 #include "RNA_access.h"
72 #include "RNA_define.h"
73
74 #include "UI_interface.h"
75 #include "UI_resources.h"
76
77 #include "render_intern.h"      // own include
78
79 /***************************** Updates ***********************************
80  * ED_render_id_flush_update gets called from DAG_id_flush_update, to do *
81  * editor level updates when the ID changes. when these ID blocks are in *
82  * the dependency graph, we can get rid of the manual dependency checks  */
83
84 static int mtex_use_tex(MTex **mtex, int tot, Tex *tex)
85 {
86         int a;
87
88         if(!mtex)
89                 return 0;
90
91         for(a=0; a<tot; a++)
92                 if(mtex[a] && mtex[a]->tex == tex)
93                         return 1;
94         
95         return 0;
96 }
97
98 static int nodes_use_tex(bNodeTree *ntree, Tex *tex)
99 {
100         bNode *node;
101
102         for(node=ntree->nodes.first; node; node= node->next) {
103                 if(node->id) {
104                         if(node->id == (ID*)tex) {
105                                 return 1;
106                         }
107                         else if(node->type==NODE_GROUP) {
108                                 if(nodes_use_tex((bNodeTree *)node->id, tex))
109                                         return 1;
110                         }
111                 }
112         }
113
114         return 0;
115 }
116
117 static void material_changed(Main *bmain, Material *ma)
118 {
119         /* icons */
120         BKE_icon_changed(BKE_icon_getid(&ma->id));
121
122         /* glsl */
123         if(ma->gpumaterial.first)
124                 GPU_material_free(ma);
125 }
126
127 static void texture_changed(Main *bmain, Tex *tex)
128 {
129         Material *ma;
130         Lamp *la;
131         World *wo;
132
133         /* icons */
134         BKE_icon_changed(BKE_icon_getid(&tex->id));
135
136         /* find materials */
137         for(ma=bmain->mat.first; ma; ma=ma->id.next) {
138                 if(mtex_use_tex(ma->mtex, MAX_MTEX, tex));
139                 else if(ma->use_nodes && ma->nodetree && nodes_use_tex(ma->nodetree, tex));
140                 else continue;
141
142                 BKE_icon_changed(BKE_icon_getid(&ma->id));
143
144                 if(ma->gpumaterial.first)
145                         GPU_material_free(ma);
146         }
147
148         /* find lamps */
149         for(la=bmain->lamp.first; la; la=la->id.next) {
150                 if(mtex_use_tex(la->mtex, MAX_MTEX, tex));
151                 else continue;
152
153                 BKE_icon_changed(BKE_icon_getid(&la->id));
154         }
155
156         /* find worlds */
157         for(wo=bmain->world.first; wo; wo=wo->id.next) {
158                 if(mtex_use_tex(wo->mtex, MAX_MTEX, tex));
159                 else continue;
160
161                 BKE_icon_changed(BKE_icon_getid(&wo->id));
162         }
163 }
164
165 static void lamp_changed(Main *bmain, Lamp *la)
166 {
167         Object *ob;
168         Material *ma;
169
170         /* icons */
171         BKE_icon_changed(BKE_icon_getid(&la->id));
172
173         /* glsl */
174         for(ob=bmain->object.first; ob; ob=ob->id.next)
175                 if(ob->data == la && ob->gpulamp.first)
176                         GPU_lamp_free(ob);
177
178         for(ma=bmain->mat.first; ma; ma=ma->id.next)
179                 if(ma->gpumaterial.first)
180                         GPU_material_free(ma);
181 }
182
183 static void world_changed(Main *bmain, World *wo)
184 {
185         Material *ma;
186
187         /* icons */
188         BKE_icon_changed(BKE_icon_getid(&wo->id));
189
190         /* glsl */
191         for(ma=bmain->mat.first; ma; ma=ma->id.next)
192                 if(ma->gpumaterial.first)
193                         GPU_material_free(ma);
194 }
195
196 void ED_render_id_flush_update(Main *bmain, ID *id)
197 {
198         switch(GS(id->name)) {
199                 case ID_MA:
200                         material_changed(bmain, (Material*)id);
201                         break;
202                 case ID_TE:
203                         texture_changed(bmain, (Tex*)id);
204                         break;
205                 case ID_WO:
206                         world_changed(bmain, (World*)id);
207                         break;
208                 case ID_LA:
209                         lamp_changed(bmain, (Lamp*)id);
210                         break;
211                 default:
212                         break;
213         }
214 }
215
216 /********************** material slot operators *********************/
217
218 static int material_slot_add_exec(bContext *C, wmOperator *op)
219 {
220         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
221
222         if(!ob)
223                 return OPERATOR_CANCELLED;
224
225         object_add_material_slot(ob);
226         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
227         
228         return OPERATOR_FINISHED;
229 }
230
231 void OBJECT_OT_material_slot_add(wmOperatorType *ot)
232 {
233         /* identifiers */
234         ot->name= "Add Material Slot";
235         ot->idname= "OBJECT_OT_material_slot_add";
236         ot->description="Add a new material slot or duplicate the selected one.";
237         
238         /* api callbacks */
239         ot->exec= material_slot_add_exec;
240
241         /* flags */
242         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
243 }
244
245 static int material_slot_remove_exec(bContext *C, wmOperator *op)
246 {
247         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
248
249         if(!ob)
250                 return OPERATOR_CANCELLED;
251
252         object_remove_material_slot(ob);
253         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
254         
255         return OPERATOR_FINISHED;
256 }
257
258 void OBJECT_OT_material_slot_remove(wmOperatorType *ot)
259 {
260         /* identifiers */
261         ot->name= "Remove Material Slot";
262         ot->idname= "OBJECT_OT_material_slot_remove";
263         ot->description="Remove the selected material slot.";
264         
265         /* api callbacks */
266         ot->exec= material_slot_remove_exec;
267
268         /* flags */
269         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
270 }
271
272 static int material_slot_assign_exec(bContext *C, wmOperator *op)
273 {
274         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
275
276         if(!ob)
277                 return OPERATOR_CANCELLED;
278
279         if(ob && ob->actcol>0) {
280                 if(ob->type == OB_MESH) {
281                         EditMesh *em= ((Mesh*)ob->data)->edit_mesh;
282                         EditFace *efa;
283
284                         if(em) {
285                                 for(efa= em->faces.first; efa; efa=efa->next)
286                                         if(efa->f & SELECT)
287                                                 efa->mat_nr= ob->actcol-1;
288                         }
289                 }
290                 else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
291                         ListBase *editnurb= ((Curve*)ob->data)->editnurb;
292                         Nurb *nu;
293
294                         if(editnurb) {
295                                 for(nu= editnurb->first; nu; nu= nu->next)
296                                         if(isNurbsel(nu))
297                                                 nu->mat_nr= nu->charidx= ob->actcol-1;
298                         }
299                 }
300                 else if(ob->type == OB_FONT) {
301                         EditFont *ef= ((Curve*)ob->data)->editfont;
302                 int i, selstart, selend;
303
304                         if(ef && BKE_font_getselection(ob, &selstart, &selend)) {
305                                 for(i=selstart; i<=selend; i++)
306                                         ef->textbufinfo[i].mat_nr = ob->actcol-1;
307                         }
308                 }
309         }
310
311     DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
312     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
313         
314         return OPERATOR_FINISHED;
315 }
316
317 void OBJECT_OT_material_slot_assign(wmOperatorType *ot)
318 {
319         /* identifiers */
320         ot->name= "Assign Material Slot";
321         ot->idname= "OBJECT_OT_material_slot_assign";
322         ot->description="Assign the material in the selected material slot to the selected vertices.";
323         
324         /* api callbacks */
325         ot->exec= material_slot_assign_exec;
326
327         /* flags */
328         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
329 }
330
331 static int material_slot_de_select(bContext *C, int select)
332 {
333         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
334
335         if(!ob)
336                 return OPERATOR_CANCELLED;
337
338         if(ob->type == OB_MESH) {
339                 EditMesh *em= ((Mesh*)ob->data)->edit_mesh;
340
341                 if(em) {
342                         if(select)
343                                 EM_select_by_material(em, ob->actcol-1);
344                         else
345                                 EM_deselect_by_material(em, ob->actcol-1);
346                 }
347         }
348         else if ELEM(ob->type, OB_CURVE, OB_SURF) {
349                 ListBase *editnurb= ((Curve*)ob->data)->editnurb;
350                 Nurb *nu;
351                 BPoint *bp;
352                 BezTriple *bezt;
353                 int a;
354
355                 for(nu= editnurb->first; nu; nu=nu->next) {
356                         if(nu->mat_nr==ob->actcol-1) {
357                                 if(nu->bezt) {
358                                         a= nu->pntsu;
359                                         bezt= nu->bezt;
360                                         while(a--) {
361                                                 if(bezt->hide==0) {
362                                                         if(select) {
363                                                                 bezt->f1 |= SELECT;
364                                                                 bezt->f2 |= SELECT;
365                                                                 bezt->f3 |= SELECT;
366                                                         }
367                                                         else {
368                                                                 bezt->f1 &= ~SELECT;
369                                                                 bezt->f2 &= ~SELECT;
370                                                                 bezt->f3 &= ~SELECT;
371                                                         }
372                                                 }
373                                                 bezt++;
374                                         }
375                                 }
376                                 else if(nu->bp) {
377                                         a= nu->pntsu*nu->pntsv;
378                                         bp= nu->bp;
379                                         while(a--) {
380                                                 if(bp->hide==0) {
381                                                         if(select) bp->f1 |= SELECT;
382                                                         else bp->f1 &= ~SELECT;
383                                                 }
384                                                 bp++;
385                                         }
386                                 }
387                         }
388                 }
389         }
390
391     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
392
393         return OPERATOR_FINISHED;
394 }
395
396 static int material_slot_select_exec(bContext *C, wmOperator *op)
397 {
398         return material_slot_de_select(C, 1);
399 }
400
401 void OBJECT_OT_material_slot_select(wmOperatorType *ot)
402 {
403         /* identifiers */
404         ot->name= "Select Material Slot";
405         ot->idname= "OBJECT_OT_material_slot_select";
406         ot->description="Select vertices assigned to the selected material slot.";
407         
408         /* api callbacks */
409         ot->exec= material_slot_select_exec;
410
411         /* flags */
412         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
413 }
414
415 static int material_slot_deselect_exec(bContext *C, wmOperator *op)
416 {
417         return material_slot_de_select(C, 0);
418 }
419
420 void OBJECT_OT_material_slot_deselect(wmOperatorType *ot)
421 {
422         /* identifiers */
423         ot->name= "Deselect Material Slot";
424         ot->idname= "OBJECT_OT_material_slot_deselect";
425         ot->description="Deselect vertices assigned to the selected material slot.";
426         
427         /* api callbacks */
428         ot->exec= material_slot_deselect_exec;
429
430         /* flags */
431         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
432 }
433
434 /********************** new material operator *********************/
435
436 static int new_material_exec(bContext *C, wmOperator *op)
437 {
438         Material *ma= CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
439         PointerRNA ptr, idptr;
440         PropertyRNA *prop;
441
442         /* add or copy material */
443         if(ma)
444                 ma= copy_material(ma);
445         else
446                 ma= add_material("Material");
447
448         /* hook into UI */
449         uiIDContextProperty(C, &ptr, &prop);
450
451         if(prop) {
452                 /* when creating new ID blocks, use is already 1, but RNA
453                  * pointer se also increases user, so this compensates it */
454                 ma->id.us--;
455
456                 RNA_id_pointer_create(&ma->id, &idptr);
457                 RNA_property_pointer_set(&ptr, prop, idptr);
458                 RNA_property_update(C, &ptr, prop);
459         }
460
461         WM_event_add_notifier(C, NC_MATERIAL|NA_ADDED, ma);
462         
463         return OPERATOR_FINISHED;
464 }
465
466 void MATERIAL_OT_new(wmOperatorType *ot)
467 {
468         /* identifiers */
469         ot->name= "New Material";
470         ot->idname= "MATERIAL_OT_new";
471         ot->description="Add a new material.";
472         
473         /* api callbacks */
474         ot->exec= new_material_exec;
475
476         /* flags */
477         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
478 }
479
480 /********************** new texture operator *********************/
481
482 static int new_texture_exec(bContext *C, wmOperator *op)
483 {
484         Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
485         PointerRNA ptr, idptr;
486         PropertyRNA *prop;
487
488         /* add or copy texture */
489         if(tex)
490                 tex= copy_texture(tex);
491         else
492                 tex= add_texture("Texture");
493
494         /* hook into UI */
495         uiIDContextProperty(C, &ptr, &prop);
496
497         if(prop) {
498                 /* when creating new ID blocks, use is already 1, but RNA
499                  * pointer se also increases user, so this compensates it */
500                 tex->id.us--;
501
502                 RNA_id_pointer_create(&tex->id, &idptr);
503                 RNA_property_pointer_set(&ptr, prop, idptr);
504                 RNA_property_update(C, &ptr, prop);
505         }
506
507         WM_event_add_notifier(C, NC_TEXTURE|NA_ADDED, tex);
508         
509         return OPERATOR_FINISHED;
510 }
511
512 void TEXTURE_OT_new(wmOperatorType *ot)
513 {
514         /* identifiers */
515         ot->name= "New Texture";
516         ot->idname= "TEXTURE_OT_new";
517         ot->description="Add a new texture.";
518         
519         /* api callbacks */
520         ot->exec= new_texture_exec;
521
522         /* flags */
523         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
524 }
525
526 /********************** new world operator *********************/
527
528 static int new_world_exec(bContext *C, wmOperator *op)
529 {
530         World *wo= CTX_data_pointer_get_type(C, "world", &RNA_World).data;
531         PointerRNA ptr, idptr;
532         PropertyRNA *prop;
533
534         /* add or copy world */
535         if(wo)
536                 wo= copy_world(wo);
537         else
538                 wo= add_world("World");
539
540         /* hook into UI */
541         uiIDContextProperty(C, &ptr, &prop);
542
543         if(prop) {
544                 /* when creating new ID blocks, use is already 1, but RNA
545                  * pointer se also increases user, so this compensates it */
546                 wo->id.us--;
547
548                 RNA_id_pointer_create(&wo->id, &idptr);
549                 RNA_property_pointer_set(&ptr, prop, idptr);
550                 RNA_property_update(C, &ptr, prop);
551         }
552
553         WM_event_add_notifier(C, NC_WORLD|NA_ADDED, wo);
554         
555         return OPERATOR_FINISHED;
556 }
557
558 void WORLD_OT_new(wmOperatorType *ot)
559 {
560         /* identifiers */
561         ot->name= "New World";
562         ot->idname= "WORLD_OT_new";
563         ot->description= "Add a new world.";
564         
565         /* api callbacks */
566         ot->exec= new_world_exec;
567
568         /* flags */
569         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
570 }
571
572 /********************** render layer operators *********************/
573
574 static int render_layer_add_exec(bContext *C, wmOperator *op)
575 {
576         Scene *scene= CTX_data_scene(C);
577
578         scene_add_render_layer(scene);
579         scene->r.actlay= BLI_countlist(&scene->r.layers) - 1;
580
581         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, scene);
582         
583         return OPERATOR_FINISHED;
584 }
585
586 void SCENE_OT_render_layer_add(wmOperatorType *ot)
587 {
588         /* identifiers */
589         ot->name= "Add Render Layer";
590         ot->idname= "SCENE_OT_render_layer_add";
591         ot->description="Add a render layer.";
592         
593         /* api callbacks */
594         ot->exec= render_layer_add_exec;
595
596         /* flags */
597         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
598 }
599
600 static int render_layer_remove_exec(bContext *C, wmOperator *op)
601 {
602         Scene *scene= CTX_data_scene(C);
603         SceneRenderLayer *rl;
604         int act= scene->r.actlay;
605
606         if(BLI_countlist(&scene->r.layers) <= 1)
607                 return OPERATOR_CANCELLED;
608         
609         rl= BLI_findlink(&scene->r.layers, scene->r.actlay);
610         BLI_remlink(&scene->r.layers, rl);
611         MEM_freeN(rl);
612
613         scene->r.actlay= 0;
614         
615         if(scene->nodetree) {
616                 bNode *node;
617                 for(node= scene->nodetree->nodes.first; node; node= node->next) {
618                         if(node->type==CMP_NODE_R_LAYERS && node->id==NULL) {
619                                 if(node->custom1==act)
620                                         node->custom1= 0;
621                                 else if(node->custom1>act)
622                                         node->custom1--;
623                         }
624                 }
625         }
626
627         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, scene);
628         
629         return OPERATOR_FINISHED;
630 }
631
632 void SCENE_OT_render_layer_remove(wmOperatorType *ot)
633 {
634         /* identifiers */
635         ot->name= "Remove Render Layer";
636         ot->idname= "SCENE_OT_render_layer_remove";
637         ot->description="Remove the selected render layer.";
638         
639         /* api callbacks */
640         ot->exec= render_layer_remove_exec;
641
642         /* flags */
643         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
644 }
645