Cycles: Direct multi light sampling in the Branched Path Integrator is optional now.
[blender-staging.git] / intern / cycles / blender / addon / ui.py
1 #
2 # Copyright 2011-2013 Blender Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License
15 #
16
17 # <pep8 compliant>
18
19 import bpy
20
21 from bpy.types import Panel, Menu, Operator
22
23
24 class CYCLES_MT_sampling_presets(Menu):
25     bl_label = "Sampling Presets"
26     preset_subdir = "cycles/sampling"
27     preset_operator = "script.execute_preset"
28     COMPAT_ENGINES = {'CYCLES'}
29     draw = Menu.draw_preset
30
31
32 class CYCLES_MT_integrator_presets(Menu):
33     bl_label = "Integrator Presets"
34     preset_subdir = "cycles/integrator"
35     preset_operator = "script.execute_preset"
36     COMPAT_ENGINES = {'CYCLES'}
37     draw = Menu.draw_preset
38
39
40 class CyclesButtonsPanel():
41     bl_space_type = "PROPERTIES"
42     bl_region_type = "WINDOW"
43     bl_context = "render"
44     COMPAT_ENGINES = {'CYCLES'}
45
46     @classmethod
47     def poll(cls, context):
48         rd = context.scene.render
49         return rd.engine in cls.COMPAT_ENGINES
50
51
52 def draw_samples_info(layout, cscene):
53     integrator = cscene.progressive
54
55     # Calculate sample values
56     if integrator == 'PATH':
57         aa = cscene.samples
58         if cscene.use_square_samples:
59             aa = aa * aa
60     else:
61         aa = cscene.aa_samples
62         d = cscene.diffuse_samples
63         g = cscene.glossy_samples
64         t = cscene.transmission_samples
65         ao = cscene.ao_samples
66         ml = cscene.mesh_light_samples
67         sss = cscene.subsurface_samples
68         vol = cscene.volume_samples
69
70         if cscene.use_square_samples:
71             aa = aa * aa
72             d = d * d
73             g = g * g
74             t = t * t
75             ao = ao * ao
76             ml = ml * ml
77             sss = sss * sss
78             vol = vol * vol
79
80     # Draw interface
81     # Do not draw for progressive, when Square Samples are disabled
82     if (integrator == 'BRANCHED_PATH') or (cscene.use_square_samples and integrator == 'PATH'):
83         col = layout.column(align=True)
84         col.scale_y = 0.6
85         col.label("Total Samples:")
86         col.separator()
87         if integrator == 'PATH':
88             col.label("%s AA" % aa)
89         else:
90             col.label("%s AA, %s Diffuse, %s Glossy, %s Transmission" %
91                       (aa, d * aa, g * aa, t * aa))
92             col.separator()
93             col.label("%s AO, %s Mesh Light, %s Subsurface, %s Volume" %
94                       (ao * aa, ml * aa, sss * aa, vol * aa))
95
96
97 class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
98     bl_label = "Sampling"
99     bl_options = {'DEFAULT_CLOSED'}
100
101     def draw(self, context):
102         layout = self.layout
103
104         scene = context.scene
105         cscene = scene.cycles
106         device_type = context.user_preferences.system.compute_device_type
107
108         row = layout.row(align=True)
109         row.menu("CYCLES_MT_sampling_presets", text=bpy.types.CYCLES_MT_sampling_presets.bl_label)
110         row.operator("render.cycles_sampling_preset_add", text="", icon="ZOOMIN")
111         row.operator("render.cycles_sampling_preset_add", text="", icon="ZOOMOUT").remove_active = True
112
113         row = layout.row()
114         row.prop(cscene, "progressive", text="")
115         row.prop(cscene, "use_square_samples")
116
117         split = layout.split()
118
119         col = split.column()
120         sub = col.column(align=True)
121         sub.label("Settings:")
122         sub.prop(cscene, "seed")
123         sub.prop(cscene, "sample_clamp_direct")
124         sub.prop(cscene, "sample_clamp_indirect")
125
126         if cscene.progressive == 'PATH':
127             col = split.column()
128             sub = col.column(align=True)
129             sub.label(text="Samples:")
130             sub.prop(cscene, "samples", text="Render")
131             sub.prop(cscene, "preview_samples", text="Preview")
132         else:
133             sub.label(text="AA Samples:")
134             sub.prop(cscene, "aa_samples", text="Render")
135             sub.prop(cscene, "preview_aa_samples", text="Preview")
136             sub.separator()
137             sub.prop(cscene, "sample_all_lights_direct")
138             sub.prop(cscene, "sample_all_lights_indirect")
139
140             col = split.column()
141             sub = col.column(align=True)
142             sub.label(text="Samples:")
143             sub.prop(cscene, "diffuse_samples", text="Diffuse")
144             sub.prop(cscene, "glossy_samples", text="Glossy")
145             sub.prop(cscene, "transmission_samples", text="Transmission")
146             sub.prop(cscene, "ao_samples", text="AO")
147             sub.prop(cscene, "mesh_light_samples", text="Mesh Light")
148             sub.prop(cscene, "subsurface_samples", text="Subsurface")
149             sub.prop(cscene, "volume_samples", text="Volume")
150
151         if cscene.feature_set == 'EXPERIMENTAL' and (device_type == 'NONE' or cscene.device == 'CPU'):
152             layout.row().prop(cscene, "sampling_pattern", text="Pattern")
153
154         for rl in scene.render.layers:
155             if rl.samples > 0:
156                 layout.separator()
157                 layout.row().prop(cscene, "use_layer_samples")
158                 break
159
160         draw_samples_info(layout, cscene)
161
162
163 class CyclesRender_PT_volume_sampling(CyclesButtonsPanel, Panel):
164     bl_label = "Volume Sampling"
165     bl_options = {'DEFAULT_CLOSED'}
166
167     def draw(self, context):
168         layout = self.layout
169
170         scene = context.scene
171         cscene = scene.cycles
172
173         split = layout.split(align=True)
174
175         sub = split.column(align=True)
176         sub.label("Heterogeneous:")
177         sub.prop(cscene, "volume_step_size")
178         sub.prop(cscene, "volume_max_steps")
179
180         sub = split.column(align=True)
181         sub.label("Homogeneous:")
182         sub.prop(cscene, "volume_homogeneous_sampling", text="")
183
184
185 class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel):
186     bl_label = "Light Paths"
187     bl_options = {'DEFAULT_CLOSED'}
188
189     def draw(self, context):
190         layout = self.layout
191
192         scene = context.scene
193         cscene = scene.cycles
194
195         row = layout.row(align=True)
196         row.menu("CYCLES_MT_integrator_presets", text=bpy.types.CYCLES_MT_integrator_presets.bl_label)
197         row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMIN")
198         row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMOUT").remove_active = True
199
200         split = layout.split()
201
202         col = split.column()
203
204         sub = col.column(align=True)
205         sub.label("Transparency:")
206         sub.prop(cscene, "transparent_max_bounces", text="Max")
207         sub.prop(cscene, "transparent_min_bounces", text="Min")
208         sub.prop(cscene, "use_transparent_shadows", text="Shadows")
209
210         col.separator()
211
212         col.prop(cscene, "no_caustics")
213         col.prop(cscene, "blur_glossy")
214
215         col = split.column()
216
217         sub = col.column(align=True)
218         sub.label(text="Bounces:")
219         sub.prop(cscene, "max_bounces", text="Max")
220         sub.prop(cscene, "min_bounces", text="Min")
221
222         sub = col.column(align=True)
223         sub.prop(cscene, "diffuse_bounces", text="Diffuse")
224         sub.prop(cscene, "glossy_bounces", text="Glossy")
225         sub.prop(cscene, "transmission_bounces", text="Transmission")
226         sub.prop(cscene, "volume_bounces", text="Volume")
227
228
229 class CyclesRender_PT_motion_blur(CyclesButtonsPanel, Panel):
230     bl_label = "Motion Blur"
231     bl_options = {'DEFAULT_CLOSED'}
232
233     def draw_header(self, context):
234         rd = context.scene.render
235
236         self.layout.prop(rd, "use_motion_blur", text="")
237
238     def draw(self, context):
239         layout = self.layout
240
241         rd = context.scene.render
242         layout.active = rd.use_motion_blur
243
244         row = layout.row()
245         row.prop(rd, "motion_blur_shutter")
246
247
248 class CyclesRender_PT_film(CyclesButtonsPanel, Panel):
249     bl_label = "Film"
250
251     def draw(self, context):
252         layout = self.layout
253
254         scene = context.scene
255         cscene = scene.cycles
256
257         split = layout.split()
258
259         col = split.column()
260         col.prop(cscene, "film_exposure")
261         col.prop(cscene, "film_transparent")
262
263         col = split.column()
264         sub = col.column(align=True)
265         sub.prop(cscene, "filter_type", text="")
266         if cscene.filter_type != 'BOX':
267             sub.prop(cscene, "filter_width", text="Width")
268
269
270 class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
271     bl_label = "Performance"
272     bl_options = {'DEFAULT_CLOSED'}
273
274     def draw(self, context):
275         layout = self.layout
276
277         scene = context.scene
278         rd = scene.render
279         cscene = scene.cycles
280
281         split = layout.split()
282
283         col = split.column(align=True)
284
285         col.label(text="Threads:")
286         col.row(align=True).prop(rd, "threads_mode", expand=True)
287         sub = col.column(align=True)
288         sub.enabled = rd.threads_mode == 'FIXED'
289         sub.prop(rd, "threads")
290
291         sub = col.column(align=True)
292         sub.label(text="Tiles:")
293         sub.prop(cscene, "tile_order", text="")
294
295         sub.prop(rd, "tile_x", text="X")
296         sub.prop(rd, "tile_y", text="Y")
297
298         sub.prop(cscene, "use_progressive_refine")
299
300         subsub = sub.column(align=True)
301         subsub.enabled = not rd.use_border
302         subsub.prop(rd, "use_save_buffers")
303
304         col = split.column(align=True)
305
306         col.label(text="Viewport:")
307         col.prop(cscene, "debug_bvh_type", text="")
308         col.separator()
309         col.prop(cscene, "preview_start_resolution")
310
311         col.separator()
312
313         col.label(text="Final Render:")
314         col.prop(cscene, "use_cache")
315         col.prop(rd, "use_persistent_data", text="Persistent Images")
316
317         col.separator()
318
319         col.label(text="Acceleration structure:")
320         col.prop(cscene, "debug_use_spatial_splits")
321
322
323 class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel):
324     bl_label = "Layer"
325     bl_context = "render_layer"
326
327     def draw(self, context):
328         layout = self.layout
329
330         scene = context.scene
331         rd = scene.render
332         rl = rd.layers.active
333
334         split = layout.split()
335
336         col = split.column()
337         col.prop(scene, "layers", text="Scene")
338         col.prop(rl, "layers_exclude", text="Exclude")
339
340         col = split.column()
341         col.prop(rl, "layers", text="Layer")
342         col.prop(rl, "layers_zmask", text="Mask Layer")
343
344         split = layout.split()
345
346         col = split.column()
347         col.label(text="Material:")
348         col.prop(rl, "material_override", text="")
349         col.separator()
350         col.prop(rl, "samples")
351
352         col = split.column()
353         col.prop(rl, "use_sky", "Use Environment")
354         col.prop(rl, "use_solid", "Use Surfaces")
355         col.prop(rl, "use_strand", "Use Hair")
356
357
358 class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel):
359     bl_label = "Passes"
360     bl_context = "render_layer"
361     bl_options = {'DEFAULT_CLOSED'}
362
363     def draw(self, context):
364         layout = self.layout
365
366         scene = context.scene
367         rd = scene.render
368         rl = rd.layers.active
369
370         split = layout.split()
371
372         col = split.column()
373         col.prop(rl, "use_pass_combined")
374         col.prop(rl, "use_pass_z")
375         col.prop(rl, "use_pass_mist")
376         col.prop(rl, "use_pass_normal")
377         col.prop(rl, "use_pass_vector")
378         col.prop(rl, "use_pass_uv")
379         col.prop(rl, "use_pass_object_index")
380         col.prop(rl, "use_pass_material_index")
381         col.separator()
382         col.prop(rl, "use_pass_shadow")
383         col.prop(rl, "use_pass_ambient_occlusion")
384         col.separator()
385         col.prop(rl, "pass_alpha_threshold")
386
387         col = split.column()
388         col.label(text="Diffuse:")
389         row = col.row(align=True)
390         row.prop(rl, "use_pass_diffuse_direct", text="Direct", toggle=True)
391         row.prop(rl, "use_pass_diffuse_indirect", text="Indirect", toggle=True)
392         row.prop(rl, "use_pass_diffuse_color", text="Color", toggle=True)
393         col.label(text="Glossy:")
394         row = col.row(align=True)
395         row.prop(rl, "use_pass_glossy_direct", text="Direct", toggle=True)
396         row.prop(rl, "use_pass_glossy_indirect", text="Indirect", toggle=True)
397         row.prop(rl, "use_pass_glossy_color", text="Color", toggle=True)
398         col.label(text="Transmission:")
399         row = col.row(align=True)
400         row.prop(rl, "use_pass_transmission_direct", text="Direct", toggle=True)
401         row.prop(rl, "use_pass_transmission_indirect", text="Indirect", toggle=True)
402         row.prop(rl, "use_pass_transmission_color", text="Color", toggle=True)
403         col.label(text="Subsurface:")
404         row = col.row(align=True)
405         row.prop(rl, "use_pass_subsurface_direct", text="Direct", toggle=True)
406         row.prop(rl, "use_pass_subsurface_indirect", text="Indirect", toggle=True)
407         row.prop(rl, "use_pass_subsurface_color", text="Color", toggle=True)
408
409         col.separator()
410         col.prop(rl, "use_pass_emit", text="Emission")
411         col.prop(rl, "use_pass_environment")
412
413
414 class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
415     bl_label = "Post Processing"
416     bl_options = {'DEFAULT_CLOSED'}
417
418     def draw(self, context):
419         layout = self.layout
420
421         rd = context.scene.render
422
423         split = layout.split()
424
425         col = split.column()
426         col.prop(rd, "use_compositing")
427         col.prop(rd, "use_sequencer")
428
429         col = split.column()
430         col.prop(rd, "dither_intensity", text="Dither", slider=True)
431
432
433 class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel):
434     bl_label = "Depth of Field"
435     bl_context = "data"
436
437     @classmethod
438     def poll(cls, context):
439         return context.camera and CyclesButtonsPanel.poll(context)
440
441     def draw(self, context):
442         layout = self.layout
443
444         cam = context.camera
445         ccam = cam.cycles
446
447         split = layout.split()
448
449         col = split.column()
450         col.label("Focus:")
451         col.prop(cam, "dof_object", text="")
452
453         sub = col.row()
454         sub.active = cam.dof_object is None
455         sub.prop(cam, "dof_distance", text="Distance")
456
457         col = split.column()
458
459         col.label("Aperture:")
460         sub = col.column(align=True)
461         sub.prop(ccam, "aperture_type", text="")
462         if ccam.aperture_type == 'RADIUS':
463             sub.prop(ccam, "aperture_size", text="Size")
464         elif ccam.aperture_type == 'FSTOP':
465             sub.prop(ccam, "aperture_fstop", text="Number")
466
467         sub = col.column(align=True)
468         sub.prop(ccam, "aperture_blades", text="Blades")
469         sub.prop(ccam, "aperture_rotation", text="Rotation")
470
471
472 class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
473     bl_label = ""
474     bl_context = "material"
475     bl_options = {'HIDE_HEADER'}
476
477     @classmethod
478     def poll(cls, context):
479         return (context.material or context.object) and CyclesButtonsPanel.poll(context)
480
481     def draw(self, context):
482         layout = self.layout
483
484         mat = context.material
485         ob = context.object
486         slot = context.material_slot
487         space = context.space_data
488
489         if ob:
490             row = layout.row()
491
492             row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=1)
493
494             col = row.column(align=True)
495             col.operator("object.material_slot_add", icon='ZOOMIN', text="")
496             col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
497
498             col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
499
500             if ob.mode == 'EDIT':
501                 row = layout.row(align=True)
502                 row.operator("object.material_slot_assign", text="Assign")
503                 row.operator("object.material_slot_select", text="Select")
504                 row.operator("object.material_slot_deselect", text="Deselect")
505
506         split = layout.split(percentage=0.65)
507
508         if ob:
509             split.template_ID(ob, "active_material", new="material.new")
510             row = split.row()
511
512             if slot:
513                 row.prop(slot, "link", text="")
514             else:
515                 row.label()
516         elif mat:
517             split.template_ID(space, "pin_id")
518             split.separator()
519
520
521 class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
522     bl_label = "Displacement"
523     bl_context = "data"
524
525     @classmethod
526     def poll(cls, context):
527         if CyclesButtonsPanel.poll(context):
528             if context.mesh or context.curve or context.meta_ball:
529                 if context.scene.cycles.feature_set == 'EXPERIMENTAL':
530                     return True
531
532         return False
533
534     def draw(self, context):
535         layout = self.layout
536
537         mesh = context.mesh
538         curve = context.curve
539         mball = context.meta_ball
540
541         if mesh:
542             cdata = mesh.cycles
543         elif curve:
544             cdata = curve.cycles
545         elif mball:
546             cdata = mball.cycles
547
548         layout.prop(cdata, "displacement_method", text="Method")
549         layout.prop(cdata, "use_subdivision")
550         layout.prop(cdata, "dicing_rate")
551
552
553 class Cycles_PT_mesh_normals(CyclesButtonsPanel, Panel):
554     bl_label = "Normals"
555     bl_context = "data"
556
557     @classmethod
558     def poll(cls, context):
559         return CyclesButtonsPanel.poll(context) and context.mesh
560
561     def draw(self, context):
562         layout = self.layout
563
564         mesh = context.mesh
565
566         split = layout.split()
567
568         col = split.column()
569         col.prop(mesh, "show_double_sided")
570
571         col = split.column()
572         col.label()
573
574
575 class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
576     bl_label = "Ray Visibility"
577     bl_context = "object"
578     bl_options = {'DEFAULT_CLOSED'}
579
580     @classmethod
581     def poll(cls, context):
582         ob = context.object
583         return (CyclesButtonsPanel.poll(context) and
584                 ob and ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'LAMP'})
585
586     def draw(self, context):
587         layout = self.layout
588
589         ob = context.object
590         visibility = ob.cycles_visibility
591
592         flow = layout.column_flow()
593
594         flow.prop(visibility, "camera")
595         flow.prop(visibility, "diffuse")
596         flow.prop(visibility, "glossy")
597         flow.prop(visibility, "transmission")
598
599         if ob.type != 'LAMP':
600             flow.prop(visibility, "shadow")
601
602
603 class CYCLES_OT_use_shading_nodes(Operator):
604     """Enable nodes on a material, world or lamp"""
605     bl_idname = "cycles.use_shading_nodes"
606     bl_label = "Use Nodes"
607
608     @classmethod
609     def poll(cls, context):
610         return context.material or context.world or context.lamp
611
612     def execute(self, context):
613         if context.material:
614             context.material.use_nodes = True
615         elif context.world:
616             context.world.use_nodes = True
617         elif context.lamp:
618             context.lamp.use_nodes = True
619
620         return {'FINISHED'}
621
622
623 def find_node(material, nodetype):
624     if material and material.node_tree:
625         ntree = material.node_tree
626
627         for node in ntree.nodes:
628             if getattr(node, "type", None) == nodetype:
629                 return node
630
631     return None
632
633
634 def find_node_input(node, name):
635     for input in node.inputs:
636         if input.name == name:
637             return input
638
639     return None
640
641
642 def panel_node_draw(layout, id_data, output_type, input_name):
643     if not id_data.use_nodes:
644         layout.operator("cycles.use_shading_nodes", icon='NODETREE')
645         return False
646
647     ntree = id_data.node_tree
648
649     node = find_node(id_data, output_type)
650     if not node:
651         layout.label(text="No output node")
652     else:
653         input = find_node_input(node, input_name)
654         layout.template_node_view(ntree, node, input)
655
656     return True
657
658
659 class CyclesLamp_PT_preview(CyclesButtonsPanel, Panel):
660     bl_label = "Preview"
661     bl_context = "data"
662     bl_options = {'DEFAULT_CLOSED'}
663
664     @classmethod
665     def poll(cls, context):
666         return context.lamp and CyclesButtonsPanel.poll(context)
667
668     def draw(self, context):
669         self.layout.template_preview(context.lamp)
670
671
672 class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
673     bl_label = "Lamp"
674     bl_context = "data"
675
676     @classmethod
677     def poll(cls, context):
678         return context.lamp and CyclesButtonsPanel.poll(context)
679
680     def draw(self, context):
681         layout = self.layout
682
683         lamp = context.lamp
684         clamp = lamp.cycles
685         cscene = context.scene.cycles
686
687         layout.prop(lamp, "type", expand=True)
688
689         split = layout.split()
690         col = split.column(align=True)
691
692         if lamp.type in {'POINT', 'SUN', 'SPOT'}:
693             col.prop(lamp, "shadow_soft_size", text="Size")
694         elif lamp.type == 'AREA':
695             col.prop(lamp, "shape", text="")
696             sub = col.column(align=True)
697
698             if lamp.shape == 'SQUARE':
699                 sub.prop(lamp, "size")
700             elif lamp.shape == 'RECTANGLE':
701                 sub.prop(lamp, "size", text="Size X")
702                 sub.prop(lamp, "size_y", text="Size Y")
703
704         if cscene.progressive == 'BRANCHED_PATH':
705             col.prop(clamp, "samples")
706
707         col = split.column()
708         col.prop(clamp, "cast_shadow")
709
710         layout.prop(clamp, "use_multiple_importance_sampling")
711
712         if lamp.type == 'HEMI':
713             layout.label(text="Not supported, interpreted as sun lamp")
714
715
716 class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
717     bl_label = "Nodes"
718     bl_context = "data"
719
720     @classmethod
721     def poll(cls, context):
722         return context.lamp and CyclesButtonsPanel.poll(context)
723
724     def draw(self, context):
725         layout = self.layout
726
727         lamp = context.lamp
728         if not panel_node_draw(layout, lamp, 'OUTPUT_LAMP', 'Surface'):
729             layout.prop(lamp, "color")
730
731
732 class CyclesLamp_PT_spot(CyclesButtonsPanel, Panel):
733     bl_label = "Spot Shape"
734     bl_context = "data"
735
736     @classmethod
737     def poll(cls, context):
738         lamp = context.lamp
739         return (lamp and lamp.type == 'SPOT') and CyclesButtonsPanel.poll(context)
740
741     def draw(self, context):
742         layout = self.layout
743
744         lamp = context.lamp
745
746         split = layout.split()
747
748         col = split.column()
749         sub = col.column()
750         sub.prop(lamp, "spot_size", text="Size")
751         sub.prop(lamp, "spot_blend", text="Blend", slider=True)
752
753         col = split.column()
754         col.prop(lamp, "show_cone")
755
756
757 class CyclesWorld_PT_preview(CyclesButtonsPanel, Panel):
758     bl_label = "Preview"
759     bl_context = "world"
760     bl_options = {'DEFAULT_CLOSED'}
761
762     @classmethod
763     def poll(cls, context):
764         return context.world and CyclesButtonsPanel.poll(context)
765
766     def draw(self, context):
767         self.layout.template_preview(context.world)
768
769
770 class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel):
771     bl_label = "Surface"
772     bl_context = "world"
773
774     @classmethod
775     def poll(cls, context):
776         return context.world and CyclesButtonsPanel.poll(context)
777
778     def draw(self, context):
779         layout = self.layout
780
781         world = context.world
782
783         if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
784             layout.prop(world, "horizon_color", text="Color")
785
786
787 class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel):
788     bl_label = "Volume"
789     bl_context = "world"
790     bl_options = {'DEFAULT_CLOSED'}
791
792     @classmethod
793     def poll(cls, context):
794         world = context.world
795         return world and world.node_tree and CyclesButtonsPanel.poll(context)
796
797     def draw(self, context):
798         layout = self.layout
799
800         world = context.world
801         panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
802
803         layout.prop(world.cycles, "homogeneous_volume")
804
805
806 class CyclesWorld_PT_ambient_occlusion(CyclesButtonsPanel, Panel):
807     bl_label = "Ambient Occlusion"
808     bl_context = "world"
809
810     @classmethod
811     def poll(cls, context):
812         return context.world and CyclesButtonsPanel.poll(context)
813
814     def draw_header(self, context):
815         light = context.world.light_settings
816         self.layout.prop(light, "use_ambient_occlusion", text="")
817
818     def draw(self, context):
819         layout = self.layout
820
821         light = context.world.light_settings
822
823         row = layout.row()
824         sub = row.row()
825         sub.active = light.use_ambient_occlusion
826         sub.prop(light, "ao_factor", text="Factor")
827         row.prop(light, "distance", text="Distance")
828
829
830 class CyclesWorld_PT_mist(CyclesButtonsPanel, Panel):
831     bl_label = "Mist Pass"
832     bl_context = "world"
833     bl_options = {'DEFAULT_CLOSED'}
834
835     @classmethod
836     def poll(cls, context):
837         if CyclesButtonsPanel.poll(context):
838             for rl in context.scene.render.layers:
839                 if rl.use_pass_mist:
840                     return True
841
842         return False
843
844     def draw(self, context):
845         layout = self.layout
846
847         world = context.world
848
849         split = layout.split(align=True)
850         split.prop(world.mist_settings, "start")
851         split.prop(world.mist_settings, "depth")
852
853         layout.prop(world.mist_settings, "falloff")
854
855
856 class CyclesWorld_PT_ray_visibility(CyclesButtonsPanel, Panel):
857     bl_label = "Ray Visibility"
858     bl_context = "world"
859     bl_options = {'DEFAULT_CLOSED'}
860
861     @classmethod
862     def poll(cls, context):
863         return CyclesButtonsPanel.poll(context) and context.world
864
865     def draw(self, context):
866         layout = self.layout
867
868         world = context.world
869         visibility = world.cycles_visibility
870
871         flow = layout.column_flow()
872
873         flow.prop(visibility, "camera")
874         flow.prop(visibility, "diffuse")
875         flow.prop(visibility, "glossy")
876         flow.prop(visibility, "transmission")
877
878
879 class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel):
880     bl_label = "Settings"
881     bl_context = "world"
882     bl_options = {'DEFAULT_CLOSED'}
883
884     @classmethod
885     def poll(cls, context):
886         return context.world and CyclesButtonsPanel.poll(context)
887
888     def draw(self, context):
889         layout = self.layout
890
891         world = context.world
892         cworld = world.cycles
893         cscene = context.scene.cycles
894
895         col = layout.column()
896
897         col.prop(cworld, "sample_as_light")
898         sub = col.row(align=True)
899         sub.active = cworld.sample_as_light
900         sub.prop(cworld, "sample_map_resolution")
901         if cscene.progressive == 'BRANCHED_PATH':
902             sub.prop(cworld, "samples")
903
904
905 class CyclesMaterial_PT_preview(CyclesButtonsPanel, Panel):
906     bl_label = "Preview"
907     bl_context = "material"
908     bl_options = {'DEFAULT_CLOSED'}
909
910     @classmethod
911     def poll(cls, context):
912         return context.material and CyclesButtonsPanel.poll(context)
913
914     def draw(self, context):
915         self.layout.template_preview(context.material)
916
917
918 class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel):
919     bl_label = "Surface"
920     bl_context = "material"
921
922     @classmethod
923     def poll(cls, context):
924         return context.material and CyclesButtonsPanel.poll(context)
925
926     def draw(self, context):
927         layout = self.layout
928
929         mat = context.material
930         if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'):
931             layout.prop(mat, "diffuse_color")
932
933
934 class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel):
935     bl_label = "Volume"
936     bl_context = "material"
937     bl_options = {'DEFAULT_CLOSED'}
938
939     @classmethod
940     def poll(cls, context):
941         mat = context.material
942         return mat and mat.node_tree and CyclesButtonsPanel.poll(context)
943
944     def draw(self, context):
945         layout = self.layout
946
947         mat = context.material
948         cmat = mat.cycles
949
950         panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
951
952         layout.prop(cmat, "homogeneous_volume")
953
954
955 class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
956     bl_label = "Displacement"
957     bl_context = "material"
958
959     @classmethod
960     def poll(cls, context):
961         mat = context.material
962         return mat and mat.node_tree and CyclesButtonsPanel.poll(context)
963
964     def draw(self, context):
965         layout = self.layout
966
967         mat = context.material
968         panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
969
970
971 class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
972     bl_label = "Settings"
973     bl_context = "material"
974     bl_options = {'DEFAULT_CLOSED'}
975
976     @classmethod
977     def poll(cls, context):
978         return context.material and CyclesButtonsPanel.poll(context)
979
980     def draw(self, context):
981         layout = self.layout
982
983         mat = context.material
984         cmat = mat.cycles
985
986         split = layout.split()
987
988         col = split.column(align=True)
989         col.prop(mat, "diffuse_color", text="Viewport Color")
990         col.prop(mat, "alpha")
991
992         col = split.column(align=True)
993         col.label()
994         col.prop(mat, "pass_index")
995
996         col = layout.column()
997         col.prop(cmat, "sample_as_light")
998         col.prop(cmat, "use_transparent_shadow")
999
1000
1001 class CyclesTexture_PT_context(CyclesButtonsPanel, Panel):
1002     bl_label = ""
1003     bl_context = "texture"
1004     bl_options = {'HIDE_HEADER'}
1005     COMPAT_ENGINES = {'CYCLES'}
1006
1007     def draw(self, context):
1008         layout = self.layout
1009
1010         tex = context.texture
1011         space = context.space_data
1012         pin_id = space.pin_id
1013         use_pin_id = space.use_pin_id
1014         user = context.texture_user
1015
1016         space.use_limited_texture_context = False
1017
1018         if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)):
1019             pin_id = None
1020
1021         if not pin_id:
1022             layout.template_texture_user()
1023
1024         if user or pin_id:
1025             layout.separator()
1026
1027             split = layout.split(percentage=0.65)
1028             col = split.column()
1029
1030             if pin_id:
1031                 col.template_ID(space, "pin_id")
1032             else:
1033                 propname = context.texture_user_property.identifier
1034                 col.template_ID(user, propname, new="texture.new")
1035
1036             if tex:
1037                 split = layout.split(percentage=0.2)
1038                 split.label(text="Type:")
1039                 split.prop(tex, "type", text="")
1040
1041
1042 class CyclesTexture_PT_node(CyclesButtonsPanel, Panel):
1043     bl_label = "Node"
1044     bl_context = "texture"
1045
1046     @classmethod
1047     def poll(cls, context):
1048         node = context.texture_node
1049         return node and CyclesButtonsPanel.poll(context)
1050
1051     def draw(self, context):
1052         layout = self.layout
1053
1054         node = context.texture_node
1055         ntree = node.id_data
1056         layout.template_node_view(ntree, node, None)
1057
1058
1059 class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel):
1060     bl_label = "Mapping"
1061     bl_context = "texture"
1062
1063     @classmethod
1064     def poll(cls, context):
1065         node = context.texture_node
1066         return node and CyclesButtonsPanel.poll(context)
1067
1068     def draw(self, context):
1069         layout = self.layout
1070
1071         node = context.texture_node
1072
1073         mapping = node.texture_mapping
1074
1075         layout.prop(mapping, "vector_type", expand=True)
1076
1077         row = layout.row()
1078
1079         row.column().prop(mapping, "translation")
1080         row.column().prop(mapping, "rotation")
1081         row.column().prop(mapping, "scale")
1082
1083         layout.label(text="Projection:")
1084
1085         row = layout.row()
1086         row.prop(mapping, "mapping_x", text="")
1087         row.prop(mapping, "mapping_y", text="")
1088         row.prop(mapping, "mapping_z", text="")
1089
1090
1091 class CyclesTexture_PT_colors(CyclesButtonsPanel, Panel):
1092     bl_label = "Color"
1093     bl_context = "texture"
1094     bl_options = {'DEFAULT_CLOSED'}
1095
1096     @classmethod
1097     def poll(cls, context):
1098         # node = context.texture_node
1099         return False
1100         #return node and CyclesButtonsPanel.poll(context)
1101
1102     def draw(self, context):
1103         layout = self.layout
1104
1105         node = context.texture_node
1106
1107         mapping = node.color_mapping
1108
1109         split = layout.split()
1110
1111         col = split.column()
1112         col.label(text="Blend:")
1113         col.prop(mapping, "blend_type", text="")
1114         col.prop(mapping, "blend_factor", text="Factor")
1115         col.prop(mapping, "blend_color", text="")
1116
1117         col = split.column()
1118         col.label(text="Adjust:")
1119         col.prop(mapping, "brightness")
1120         col.prop(mapping, "contrast")
1121         col.prop(mapping, "saturation")
1122
1123         layout.separator()
1124
1125         layout.prop(mapping, "use_color_ramp", text="Ramp")
1126         if mapping.use_color_ramp:
1127             layout.template_color_ramp(mapping, "color_ramp", expand=True)
1128
1129
1130 class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
1131     bl_label = "Textures"
1132     bl_context = "particle"
1133     bl_options = {'DEFAULT_CLOSED'}
1134
1135     @classmethod
1136     def poll(cls, context):
1137         psys = context.particle_system
1138         return psys and CyclesButtonsPanel.poll(context)
1139
1140     def draw(self, context):
1141         layout = self.layout
1142
1143         psys = context.particle_system
1144         part = psys.settings
1145
1146         row = layout.row()
1147         row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2)
1148
1149         col = row.column(align=True)
1150         col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
1151         col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
1152         col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="")
1153
1154         if not part.active_texture:
1155             layout.template_ID(part, "active_texture", new="texture.new")
1156         else:
1157             slot = part.texture_slots[part.active_texture_index]
1158             layout.template_ID(slot, "texture", new="texture.new")
1159
1160
1161 class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
1162     bl_label = "Cycles Hair Rendering"
1163     bl_context = "particle"
1164
1165     @classmethod
1166     def poll(cls, context):
1167         scene = context.scene
1168         cscene = scene.cycles
1169         psys = context.particle_system
1170         return CyclesButtonsPanel.poll(context) and psys and psys.settings.type == 'HAIR'
1171
1172     def draw_header(self, context):
1173         ccscene = context.scene.cycles_curves
1174         self.layout.prop(ccscene, "use_curves", text="")
1175
1176     def draw(self, context):
1177         layout = self.layout
1178
1179         scene = context.scene
1180         ccscene = scene.cycles_curves
1181
1182         layout.active = ccscene.use_curves
1183
1184         layout.prop(ccscene, "primitive", text="Primitive")
1185         layout.prop(ccscene, "shape", text="Shape")
1186
1187         if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'):
1188             layout.prop(ccscene, "cull_backfacing", text="Cull back-faces")
1189
1190         if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK':
1191             layout.prop(ccscene, "resolution", text="Resolution")
1192         elif ccscene.primitive == 'CURVE_SEGMENTS':
1193             layout.prop(ccscene, "subdivisions", text="Curve subdivisions")
1194
1195         row = layout.row()
1196         row.prop(ccscene, "minimum_width", text="Min Pixels")
1197         row.prop(ccscene, "maximum_width", text="Max Ext.")
1198
1199
1200 class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
1201     bl_label = "Cycles Hair Settings"
1202     bl_context = "particle"
1203
1204     @classmethod
1205     def poll(cls, context):
1206         scene = context.scene
1207         cscene = scene.cycles
1208         ccscene = scene.cycles_curves
1209         psys = context.particle_system
1210         use_curves = ccscene.use_curves and psys
1211         return CyclesButtonsPanel.poll(context) and use_curves and psys.settings.type == 'HAIR'
1212
1213     def draw(self, context):
1214         layout = self.layout
1215
1216         psys = context.particle_settings
1217         cpsys = psys.cycles
1218
1219         row = layout.row()
1220         row.prop(cpsys, "shape", text="Shape")
1221
1222         layout.label(text="Thickness:")
1223         row = layout.row()
1224         row.prop(cpsys, "root_width", text="Root")
1225         row.prop(cpsys, "tip_width", text="Tip")
1226
1227         row = layout.row()
1228         row.prop(cpsys, "radius_scale", text="Scaling")
1229         row.prop(cpsys, "use_closetip", text="Close tip")
1230
1231
1232 class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
1233     bl_label = "Simplify"
1234     bl_context = "scene"
1235     COMPAT_ENGINES = {'CYCLES'}
1236
1237     def draw_header(self, context):
1238         rd = context.scene.render
1239         self.layout.prop(rd, "use_simplify", text="")
1240
1241     def draw(self, context):
1242         layout = self.layout
1243
1244         rd = context.scene.render
1245
1246         layout.active = rd.use_simplify
1247
1248         row = layout.row()
1249         row.prop(rd, "simplify_subdivision", text="Subdivision")
1250         row.prop(rd, "simplify_child_particles", text="Child Particles")
1251
1252
1253 def draw_device(self, context):
1254     scene = context.scene
1255     layout = self.layout
1256
1257     if scene.render.engine == 'CYCLES':
1258         from . import engine
1259         cscene = scene.cycles
1260
1261         layout.prop(cscene, "feature_set")
1262
1263         device_type = context.user_preferences.system.compute_device_type
1264         if device_type in {'CUDA', 'OPENCL', 'NETWORK'}:
1265             layout.prop(cscene, "device")
1266
1267         if engine.with_osl() and (cscene.device == 'CPU' or device_type == 'NONE'):
1268             layout.prop(cscene, "shading_system")
1269
1270
1271 def draw_pause(self, context):
1272     layout = self.layout
1273     scene = context.scene
1274
1275     if scene.render.engine == "CYCLES":
1276         view = context.space_data
1277
1278         if view.viewport_shade == 'RENDERED':
1279             cscene = scene.cycles
1280             layername = scene.render.layers.active.name
1281             layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
1282             layout.prop(cscene, "preview_active_layer", icon="RENDERLAYERS", text=layername)
1283
1284
1285 def get_panels():
1286     types = bpy.types
1287     panels = [
1288         "RENDER_PT_render",
1289         "RENDER_PT_output",
1290         "RENDER_PT_encoding",
1291         "RENDER_PT_dimensions",
1292         "RENDER_PT_stamp",
1293         "RENDERLAYER_PT_layers",
1294         "SCENE_PT_scene",
1295         "SCENE_PT_color_management",
1296         "SCENE_PT_custom_props",
1297         "SCENE_PT_audio",
1298         "SCENE_PT_unit",
1299         "SCENE_PT_keying_sets",
1300         "SCENE_PT_keying_set_paths",
1301         "SCENE_PT_physics",
1302         "WORLD_PT_context_world",
1303         "WORLD_PT_custom_props",
1304         "DATA_PT_context_mesh",
1305         "DATA_PT_context_camera",
1306         "DATA_PT_context_lamp",
1307         "DATA_PT_context_speaker",
1308         "DATA_PT_texture_space",
1309         "DATA_PT_curve_texture_space",
1310         "DATA_PT_mball_texture_space",
1311         "DATA_PT_vertex_groups",
1312         "DATA_PT_shape_keys",
1313         "DATA_PT_uv_texture",
1314         "DATA_PT_vertex_colors",
1315         "DATA_PT_camera",
1316         "DATA_PT_camera_display",
1317         "DATA_PT_lens",
1318         "DATA_PT_speaker",
1319         "DATA_PT_distance",
1320         "DATA_PT_cone",
1321         "DATA_PT_customdata",
1322         "DATA_PT_custom_props_mesh",
1323         "DATA_PT_custom_props_camera",
1324         "DATA_PT_custom_props_lamp",
1325         "DATA_PT_custom_props_speaker",
1326         "DATA_PT_custom_props_arm",
1327         "DATA_PT_custom_props_curve",
1328         "DATA_PT_custom_props_lattice",
1329         "DATA_PT_custom_props_metaball",
1330         "TEXTURE_PT_custom_props",
1331         "TEXTURE_PT_clouds",
1332         "TEXTURE_PT_wood",
1333         "TEXTURE_PT_marble",
1334         "TEXTURE_PT_magic",
1335         "TEXTURE_PT_blend",
1336         "TEXTURE_PT_stucci",
1337         "TEXTURE_PT_image",
1338         "TEXTURE_PT_image_sampling",
1339         "TEXTURE_PT_image_mapping",
1340         "TEXTURE_PT_musgrave",
1341         "TEXTURE_PT_voronoi",
1342         "TEXTURE_PT_distortednoise",
1343         "TEXTURE_PT_voxeldata",
1344         "TEXTURE_PT_pointdensity",
1345         "TEXTURE_PT_pointdensity_turbulence",
1346         "TEXTURE_PT_mapping",
1347         "TEXTURE_PT_influence",
1348         "TEXTURE_PT_colors",
1349         "PARTICLE_PT_context_particles",
1350         "PARTICLE_PT_custom_props",
1351         "PARTICLE_PT_emission",
1352         "PARTICLE_PT_hair_dynamics",
1353         "PARTICLE_PT_cache",
1354         "PARTICLE_PT_velocity",
1355         "PARTICLE_PT_rotation",
1356         "PARTICLE_PT_physics",
1357         "SCENE_PT_rigid_body_world",
1358         "SCENE_PT_rigid_body_cache",
1359         "SCENE_PT_rigid_body_field_weights",
1360         "PARTICLE_PT_boidbrain",
1361         "PARTICLE_PT_render",
1362         "PARTICLE_PT_draw",
1363         "PARTICLE_PT_children",
1364         "PARTICLE_PT_field_weights",
1365         "PARTICLE_PT_force_fields",
1366         "PARTICLE_PT_vertexgroups",
1367         "MATERIAL_PT_custom_props",
1368         "BONE_PT_custom_props",
1369         "OBJECT_PT_custom_props",
1370         ]
1371
1372     return [getattr(types, p) for p in panels if hasattr(types, p)]
1373
1374
1375 def register():
1376     bpy.types.RENDER_PT_render.append(draw_device)
1377     bpy.types.VIEW3D_HT_header.append(draw_pause)
1378
1379     for panel in get_panels():
1380         panel.COMPAT_ENGINES.add('CYCLES')
1381
1382
1383 def unregister():
1384     bpy.types.RENDER_PT_render.remove(draw_device)
1385     bpy.types.VIEW3D_HT_header.remove(draw_pause)
1386
1387     for panel in get_panels():
1388         panel.COMPAT_ENGINES.remove('CYCLES')