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