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