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