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