Cycles: add animation denoising Python operator.
[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 import _cycles
21
22 from bpy.types import (
23     Panel,
24     Menu,
25 )
26
27
28 class CYCLES_MT_sampling_presets(Menu):
29     bl_label = "Sampling Presets"
30     preset_subdir = "cycles/sampling"
31     preset_operator = "script.execute_preset"
32     COMPAT_ENGINES = {'CYCLES'}
33     draw = Menu.draw_preset
34
35
36 class CYCLES_MT_integrator_presets(Menu):
37     bl_label = "Integrator Presets"
38     preset_subdir = "cycles/integrator"
39     preset_operator = "script.execute_preset"
40     COMPAT_ENGINES = {'CYCLES'}
41     draw = Menu.draw_preset
42
43
44 class CyclesButtonsPanel:
45     bl_space_type = "PROPERTIES"
46     bl_region_type = "WINDOW"
47     bl_context = "render"
48     COMPAT_ENGINES = {'CYCLES'}
49
50     @classmethod
51     def poll(cls, context):
52         rd = context.scene.render
53         return rd.engine in cls.COMPAT_ENGINES
54
55
56 def get_device_type(context):
57     return context.user_preferences.addons[__package__].preferences.compute_device_type
58
59
60 def use_cpu(context):
61     cscene = context.scene.cycles
62
63     return (get_device_type(context) == 'NONE' or cscene.device == 'CPU')
64
65
66 def use_opencl(context):
67     cscene = context.scene.cycles
68
69     return (get_device_type(context) == 'OPENCL' and cscene.device == 'GPU')
70
71
72 def use_cuda(context):
73     cscene = context.scene.cycles
74
75     return (get_device_type(context) == 'CUDA' and cscene.device == 'GPU')
76
77
78 def use_branched_path(context):
79     cscene = context.scene.cycles
80
81     return (cscene.progressive == 'BRANCHED_PATH')
82
83
84 def use_sample_all_lights(context):
85     cscene = context.scene.cycles
86
87     return cscene.sample_all_lights_direct or cscene.sample_all_lights_indirect
88
89
90 def show_device_active(context):
91     cscene = context.scene.cycles
92     if cscene.device != 'GPU':
93         return True
94     return context.user_preferences.addons[__package__].preferences.has_active_device()
95
96
97 def draw_samples_info(layout, context):
98     cscene = context.scene.cycles
99     integrator = cscene.progressive
100
101     # Calculate sample values
102     if integrator == 'PATH':
103         aa = cscene.samples
104         if cscene.use_square_samples:
105             aa = aa * aa
106     else:
107         aa = cscene.aa_samples
108         d = cscene.diffuse_samples
109         g = cscene.glossy_samples
110         t = cscene.transmission_samples
111         ao = cscene.ao_samples
112         ml = cscene.mesh_light_samples
113         sss = cscene.subsurface_samples
114         vol = cscene.volume_samples
115
116         if cscene.use_square_samples:
117             aa = aa * aa
118             d = d * d
119             g = g * g
120             t = t * t
121             ao = ao * ao
122             ml = ml * ml
123             sss = sss * sss
124             vol = vol * vol
125
126     # Draw interface
127     # Do not draw for progressive, when Square Samples are disabled
128     if use_branched_path(context) or (cscene.use_square_samples and integrator == 'PATH'):
129         col = layout.column(align=True)
130         col.scale_y = 0.6
131         col.label("Total Samples:")
132         col.separator()
133         if integrator == 'PATH':
134             col.label("%s AA" % aa)
135         else:
136             col.label("%s AA, %s Diffuse, %s Glossy, %s Transmission" %
137                       (aa, d * aa, g * aa, t * aa))
138             col.separator()
139             col.label("%s AO, %s Mesh Light, %s Subsurface, %s Volume" %
140                       (ao * aa, ml * aa, sss * aa, vol * aa))
141
142
143 class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
144     bl_label = "Sampling"
145     bl_options = {'DEFAULT_CLOSED'}
146
147     def draw(self, context):
148         layout = self.layout
149
150         scene = context.scene
151         cscene = scene.cycles
152
153         row = layout.row(align=True)
154         row.menu("CYCLES_MT_sampling_presets", text=bpy.types.CYCLES_MT_sampling_presets.bl_label)
155         row.operator("render.cycles_sampling_preset_add", text="", icon="ZOOMIN")
156         row.operator("render.cycles_sampling_preset_add", text="", icon="ZOOMOUT").remove_active = True
157
158         row = layout.row()
159         sub = row.row()
160         sub.prop(cscene, "progressive", text="")
161         row.prop(cscene, "use_square_samples")
162
163         split = layout.split()
164
165         col = split.column()
166         sub = col.column(align=True)
167         sub.label("Settings:")
168
169         seed_sub = sub.row(align=True)
170         seed_sub.prop(cscene, "seed")
171         seed_sub.prop(cscene, "use_animated_seed", text="", icon="TIME")
172
173         sub.prop(cscene, "sample_clamp_direct")
174         sub.prop(cscene, "sample_clamp_indirect")
175         sub.prop(cscene, "light_sampling_threshold")
176
177         if cscene.progressive == 'PATH' or use_branched_path(context) is False:
178             col = split.column()
179             sub = col.column(align=True)
180             sub.label(text="Samples:")
181             sub.prop(cscene, "samples", text="Render")
182             sub.prop(cscene, "preview_samples", text="Preview")
183         else:
184             sub.label(text="AA Samples:")
185             sub.prop(cscene, "aa_samples", text="Render")
186             sub.prop(cscene, "preview_aa_samples", text="Preview")
187
188             col = split.column()
189             sub = col.column(align=True)
190             sub.label(text="Samples:")
191             sub.prop(cscene, "diffuse_samples", text="Diffuse")
192             sub.prop(cscene, "glossy_samples", text="Glossy")
193             sub.prop(cscene, "transmission_samples", text="Transmission")
194             sub.prop(cscene, "ao_samples", text="AO")
195
196             subsub = sub.row(align=True)
197             subsub.active = use_sample_all_lights(context)
198             subsub.prop(cscene, "mesh_light_samples", text="Mesh Light")
199
200             sub.prop(cscene, "subsurface_samples", text="Subsurface")
201             sub.prop(cscene, "volume_samples", text="Volume")
202
203             col = layout.column(align=True)
204             col.prop(cscene, "sample_all_lights_direct")
205             col.prop(cscene, "sample_all_lights_indirect")
206
207         layout.row().prop(cscene, "sampling_pattern", text="Pattern")
208
209         for rl in scene.render.layers:
210             if rl.samples > 0:
211                 layout.separator()
212                 layout.row().prop(cscene, "use_layer_samples")
213                 break
214
215         draw_samples_info(layout, context)
216
217
218 class CYCLES_RENDER_PT_geometry(CyclesButtonsPanel, Panel):
219     bl_label = "Geometry"
220     bl_options = {'DEFAULT_CLOSED'}
221
222     def draw(self, context):
223         layout = self.layout
224
225         scene = context.scene
226         cscene = scene.cycles
227         ccscene = scene.cycles_curves
228
229         row = layout.row()
230         row.label("Volume Sampling:")
231         row = layout.row()
232         row.prop(cscene, "volume_step_size")
233         row.prop(cscene, "volume_max_steps")
234
235         layout.separator()
236
237         if cscene.feature_set == 'EXPERIMENTAL':
238             layout.label("Subdivision Rate:")
239             split = layout.split()
240
241             col = split.column()
242             sub = col.column(align=True)
243             sub.prop(cscene, "dicing_rate", text="Render")
244             sub.prop(cscene, "preview_dicing_rate", text="Preview")
245
246             col = split.column()
247             col.prop(cscene, "offscreen_dicing_scale", text="Offscreen Scale")
248             col.prop(cscene, "max_subdivisions")
249
250             layout.prop(cscene, "dicing_camera")
251
252             layout.separator()
253
254         layout.label("Hair:")
255         layout.prop(ccscene, "use_curves", text="Use Hair")
256         col = layout.column()
257         col.active = ccscene.use_curves
258
259         col.prop(ccscene, "primitive", text="Primitive")
260         col.prop(ccscene, "shape", text="Shape")
261
262         if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'):
263             col.prop(ccscene, "cull_backfacing", text="Cull back-faces")
264
265         if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK':
266             col.prop(ccscene, "resolution", text="Resolution")
267         elif ccscene.primitive == 'CURVE_SEGMENTS':
268             col.prop(ccscene, "subdivisions", text="Curve subdivisions")
269
270         row = col.row()
271         row.prop(ccscene, "minimum_width", text="Min Pixels")
272         row.prop(ccscene, "maximum_width", text="Max Extension")
273
274
275 class CYCLES_RENDER_PT_light_paths(CyclesButtonsPanel, Panel):
276     bl_label = "Light Paths"
277     bl_options = {'DEFAULT_CLOSED'}
278
279     def draw(self, context):
280         layout = self.layout
281
282         scene = context.scene
283         cscene = scene.cycles
284
285         row = layout.row(align=True)
286         row.menu("CYCLES_MT_integrator_presets", text=bpy.types.CYCLES_MT_integrator_presets.bl_label)
287         row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMIN")
288         row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMOUT").remove_active = True
289
290         split = layout.split()
291
292         col = split.column()
293
294         sub = col.column(align=True)
295         sub.label("Transparency:")
296         sub.prop(cscene, "transparent_max_bounces", text="Max")
297
298         col.separator()
299
300         col.prop(cscene, "caustics_reflective")
301         col.prop(cscene, "caustics_refractive")
302         col.prop(cscene, "blur_glossy")
303
304         col = split.column()
305
306         sub = col.column(align=True)
307         sub.label(text="Bounces:")
308         sub.prop(cscene, "max_bounces", text="Max")
309
310         sub = col.column(align=True)
311         sub.prop(cscene, "diffuse_bounces", text="Diffuse")
312         sub.prop(cscene, "glossy_bounces", text="Glossy")
313         sub.prop(cscene, "transmission_bounces", text="Transmission")
314         sub.prop(cscene, "volume_bounces", text="Volume")
315
316
317 class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel):
318     bl_label = "Motion Blur"
319     bl_options = {'DEFAULT_CLOSED'}
320
321     def draw_header(self, context):
322         rd = context.scene.render
323
324         self.layout.prop(rd, "use_motion_blur", text="")
325
326     def draw(self, context):
327         layout = self.layout
328
329         scene = context.scene
330         cscene = scene.cycles
331         rd = scene.render
332         layout.active = rd.use_motion_blur
333
334         col = layout.column()
335         col.prop(cscene, "motion_blur_position", text="Position")
336         col.prop(rd, "motion_blur_shutter")
337
338         col = layout.column()
339         col.label("Shutter curve:")
340         col.template_curve_mapping(rd, "motion_blur_shutter_curve")
341
342         col = layout.column(align=True)
343         row = col.row(align=True)
344         row.operator("render.shutter_curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
345         row.operator("render.shutter_curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
346         row.operator("render.shutter_curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
347         row.operator("render.shutter_curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
348         row.operator("render.shutter_curve_preset", icon='LINCURVE', text="").shape = 'LINE'
349         row.operator("render.shutter_curve_preset", icon='NOCURVE', text="").shape = 'MAX'
350
351         col = layout.column()
352         col.prop(cscene, "rolling_shutter_type")
353         row = col.row()
354         row.active = cscene.rolling_shutter_type != 'NONE'
355         row.prop(cscene, "rolling_shutter_duration")
356
357
358 class CYCLES_RENDER_PT_film(CyclesButtonsPanel, Panel):
359     bl_label = "Film"
360
361     def draw(self, context):
362         layout = self.layout
363
364         scene = context.scene
365         cscene = scene.cycles
366
367         split = layout.split()
368
369         col = split.column()
370         col.prop(cscene, "film_exposure")
371         col.separator()
372         sub = col.column(align=True)
373         sub.prop(cscene, "pixel_filter_type", text="")
374         if cscene.pixel_filter_type != 'BOX':
375             sub.prop(cscene, "filter_width", text="Width")
376
377         col = split.column()
378         col.prop(cscene, "film_transparent")
379         sub = col.row()
380         sub.prop(cscene, "film_transparent_glass", text="Transparent Glass")
381         sub.active = cscene.film_transparent
382         sub = col.row()
383         sub.prop(cscene, "film_transparent_roughness", text="Roughness Threshold")
384         sub.active = cscene.film_transparent and cscene.film_transparent_glass
385
386
387 class CYCLES_RENDER_PT_performance(CyclesButtonsPanel, Panel):
388     bl_label = "Performance"
389     bl_options = {'DEFAULT_CLOSED'}
390
391     def draw(self, context):
392         layout = self.layout
393
394         scene = context.scene
395         rd = scene.render
396         cscene = scene.cycles
397
398         split = layout.split()
399
400         col = split.column(align=True)
401
402         col.label(text="Threads:")
403         col.row(align=True).prop(rd, "threads_mode", expand=True)
404         sub = col.column(align=True)
405         sub.enabled = rd.threads_mode == 'FIXED'
406         sub.prop(rd, "threads")
407
408         col.separator()
409
410         sub = col.column(align=True)
411         sub.label(text="Tiles:")
412         sub.prop(cscene, "tile_order", text="")
413
414         sub.prop(rd, "tile_x", text="X")
415         sub.prop(rd, "tile_y", text="Y")
416
417         subsub = sub.column()
418         subsub.active = not rd.use_save_buffers
419         for rl in rd.layers:
420             if rl.cycles.use_denoising:
421                 subsub.active = False
422         subsub.prop(cscene, "use_progressive_refine")
423
424         col = split.column()
425
426         col.label(text="Final Render:")
427         col.prop(rd, "use_save_buffers")
428         col.prop(rd, "use_persistent_data", text="Persistent Images")
429
430         col.separator()
431
432         col.label(text="Acceleration structure:")
433         if _cycles.with_embree:
434             row = col.row()
435             row.active = use_cpu(context)
436             row.prop(cscene, "use_bvh_embree")
437         row = col.row()
438         col.prop(cscene, "debug_use_spatial_splits")
439         row = col.row()
440         row.active = not cscene.use_bvh_embree or not _cycles.with_embree
441         row.prop(cscene, "debug_use_hair_bvh")
442
443         row = col.row()
444         row.active = not cscene.debug_use_spatial_splits and not cscene.use_bvh_embree
445         row.prop(cscene, "debug_bvh_time_steps")
446
447         col = layout.column()
448         col.label(text="Viewport Resolution:")
449         split = col.split()
450         split.prop(rd, "preview_pixel_size", text="")
451         split.prop(cscene, "preview_start_resolution")
452
453
454 class CYCLES_RENDER_PT_layer_options(CyclesButtonsPanel, Panel):
455     bl_label = "Layer"
456     bl_context = "render_layer"
457
458     def draw(self, context):
459         layout = self.layout
460         with_freestyle = bpy.app.build_options.freestyle
461
462         scene = context.scene
463         rd = scene.render
464         rl = rd.layers.active
465
466         split = layout.split()
467
468         col = split.column()
469         col.prop(scene, "layers", text="Scene")
470         col.prop(rl, "layers_exclude", text="Exclude")
471
472         col = split.column()
473         col.prop(rl, "layers", text="Layer")
474         col.prop(rl, "layers_zmask", text="Mask Layer")
475
476         split = layout.split()
477
478         col = split.column()
479         col.label(text="Material:")
480         col.prop(rl, "material_override", text="")
481         col.separator()
482         col.prop(rl, "samples")
483
484         col = split.column()
485         col.prop(rl, "use_sky", "Use Environment")
486         col.prop(rl, "use_ao", "Use AO")
487         col.prop(rl, "use_solid", "Use Surfaces")
488         col.prop(rl, "use_strand", "Use Hair")
489         if with_freestyle:
490             row = col.row()
491             row.prop(rl, "use_freestyle", "Use Freestyle")
492             row.active = rd.use_freestyle
493
494
495 class CYCLES_RENDER_PT_layer_passes(CyclesButtonsPanel, Panel):
496     bl_label = "Passes"
497     bl_context = "render_layer"
498     bl_options = {'DEFAULT_CLOSED'}
499
500     def draw(self, context):
501         layout = self.layout
502
503         scene = context.scene
504         rd = scene.render
505         rl = rd.layers.active
506         crl = rl.cycles
507
508         split = layout.split()
509
510         col = split.column()
511         col.prop(rl, "use_pass_combined")
512         col.prop(rl, "use_pass_z")
513         col.prop(rl, "use_pass_mist")
514         col.prop(rl, "use_pass_normal")
515         row = col.row()
516         row.prop(rl, "use_pass_vector")
517         row.active = not rd.use_motion_blur
518         col.prop(rl, "use_pass_uv")
519         col.prop(rl, "use_pass_object_index")
520         col.prop(rl, "use_pass_material_index")
521         col.separator()
522         col.prop(rl, "use_pass_shadow")
523         col.prop(rl, "use_pass_ambient_occlusion")
524         col.separator()
525         col.prop(crl, "denoising_store_passes", text="Denoising Data")
526         col.separator()
527         col.prop(rl, "pass_alpha_threshold")
528
529         col = split.column()
530         col.label(text="Diffuse:")
531         row = col.row(align=True)
532         row.prop(rl, "use_pass_diffuse_direct", text="Direct", toggle=True)
533         row.prop(rl, "use_pass_diffuse_indirect", text="Indirect", toggle=True)
534         row.prop(rl, "use_pass_diffuse_color", text="Color", toggle=True)
535         col.label(text="Glossy:")
536         row = col.row(align=True)
537         row.prop(rl, "use_pass_glossy_direct", text="Direct", toggle=True)
538         row.prop(rl, "use_pass_glossy_indirect", text="Indirect", toggle=True)
539         row.prop(rl, "use_pass_glossy_color", text="Color", toggle=True)
540         col.label(text="Transmission:")
541         row = col.row(align=True)
542         row.prop(rl, "use_pass_transmission_direct", text="Direct", toggle=True)
543         row.prop(rl, "use_pass_transmission_indirect", text="Indirect", toggle=True)
544         row.prop(rl, "use_pass_transmission_color", text="Color", toggle=True)
545         col.label(text="Subsurface:")
546         row = col.row(align=True)
547         row.prop(rl, "use_pass_subsurface_direct", text="Direct", toggle=True)
548         row.prop(rl, "use_pass_subsurface_indirect", text="Indirect", toggle=True)
549         row.prop(rl, "use_pass_subsurface_color", text="Color", toggle=True)
550         col.label(text="Volume:")
551         row = col.row(align=True)
552         row.prop(crl, "use_pass_volume_direct", text="Direct", toggle=True)
553         row.prop(crl, "use_pass_volume_indirect", text="Indirect", toggle=True)
554
555         col.separator()
556         col.prop(rl, "use_pass_emit", text="Emission")
557         col.prop(rl, "use_pass_environment")
558
559         col = layout.column()
560         col.prop(crl, "pass_debug_render_time")
561         if _cycles.with_cycles_debug:
562             col.prop(crl, "pass_debug_bvh_traversed_nodes")
563             col.prop(crl, "pass_debug_bvh_traversed_instances")
564             col.prop(crl, "pass_debug_bvh_intersections")
565             col.prop(crl, "pass_debug_ray_bounces")
566
567         crl = rl.cycles
568         layout.label("Cryptomatte:")
569         row = layout.row(align=True)
570         row.prop(crl, "use_pass_crypto_object", text="Object", toggle=True)
571         row.prop(crl, "use_pass_crypto_material", text="Material", toggle=True)
572         row.prop(crl, "use_pass_crypto_asset", text="Asset", toggle=True)
573         row = layout.row(align=True)
574         row.prop(crl, "pass_crypto_depth")
575         row = layout.row(align=True)
576         row.active = use_cpu(context)
577         row.prop(crl, "pass_crypto_accurate", text="Accurate Mode")
578
579 class CYCLES_RENDER_PT_views(CyclesButtonsPanel, Panel):
580     bl_label = "Views"
581     bl_context = "render_layer"
582     bl_options = {'DEFAULT_CLOSED'}
583
584     def draw_header(self, context):
585         rd = context.scene.render
586         self.layout.prop(rd, "use_multiview", text="")
587
588     def draw(self, context):
589         layout = self.layout
590
591         scene = context.scene
592         rd = scene.render
593         rv = rd.views.active
594
595         layout.active = rd.use_multiview
596         basic_stereo = (rd.views_format == 'STEREO_3D')
597
598         row = layout.row()
599         row.prop(rd, "views_format", expand=True)
600
601         if basic_stereo:
602             row = layout.row()
603             row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2)
604
605             row = layout.row()
606             row.label(text="File Suffix:")
607             row.prop(rv, "file_suffix", text="")
608
609         else:
610             row = layout.row()
611             row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2)
612
613             col = row.column(align=True)
614             col.operator("scene.render_view_add", icon='ZOOMIN', text="")
615             col.operator("scene.render_view_remove", icon='ZOOMOUT', text="")
616
617             row = layout.row()
618             row.label(text="Camera Suffix:")
619             row.prop(rv, "camera_suffix", text="")
620
621
622 class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
623     bl_label = "Denoising"
624     bl_context = "render_layer"
625     bl_options = {'DEFAULT_CLOSED'}
626
627     def draw_header(self, context):
628         rd = context.scene.render
629         rl = rd.layers.active
630         crl = rl.cycles
631         cscene = context.scene.cycles
632         layout = self.layout
633
634         layout.prop(crl, "use_denoising", text="")
635
636     def draw(self, context):
637         layout = self.layout
638
639         scene = context.scene
640         cscene = scene.cycles
641         rd = scene.render
642         rl = rd.layers.active
643         crl = rl.cycles
644
645         split = layout.split()
646         split.active = crl.use_denoising
647
648         col = split.column()
649         sub = col.column(align=True)
650         sub.prop(crl, "denoising_radius", text="Radius")
651         sub.prop(crl, "denoising_strength", slider=True, text="Strength")
652
653         col = split.column()
654         sub = col.column(align=True)
655         sub.prop(crl, "denoising_feature_strength", slider=True, text="Feature Strength")
656         sub.prop(crl, "denoising_relative_pca")
657
658         layout.separator()
659
660         row = layout.row()
661         row.active = crl.use_denoising or crl.denoising_store_passes
662         row.label(text="Diffuse:")
663         sub = row.row(align=True)
664         sub.prop(crl, "denoising_diffuse_direct", text="Direct", toggle=True)
665         sub.prop(crl, "denoising_diffuse_indirect", text="Indirect", toggle=True)
666
667         row = layout.row()
668         row.active = crl.use_denoising or crl.denoising_store_passes
669         row.label(text="Glossy:")
670         sub = row.row(align=True)
671         sub.prop(crl, "denoising_glossy_direct", text="Direct", toggle=True)
672         sub.prop(crl, "denoising_glossy_indirect", text="Indirect", toggle=True)
673
674         row = layout.row()
675         row.active = crl.use_denoising or crl.denoising_store_passes
676         row.label(text="Transmission:")
677         sub = row.row(align=True)
678         sub.prop(crl, "denoising_transmission_direct", text="Direct", toggle=True)
679         sub.prop(crl, "denoising_transmission_indirect", text="Indirect", toggle=True)
680
681         row = layout.row()
682         row.active = crl.use_denoising or crl.denoising_store_passes
683         row.label(text="Subsurface:")
684         sub = row.row(align=True)
685         sub.prop(crl, "denoising_subsurface_direct", text="Direct", toggle=True)
686         sub.prop(crl, "denoising_subsurface_indirect", text="Indirect", toggle=True)
687
688
689 class CYCLES_PT_post_processing(CyclesButtonsPanel, Panel):
690     bl_label = "Post Processing"
691     bl_options = {'DEFAULT_CLOSED'}
692
693     def draw(self, context):
694         layout = self.layout
695
696         rd = context.scene.render
697
698         split = layout.split()
699
700         col = split.column()
701         col.prop(rd, "use_compositing")
702         col.prop(rd, "use_sequencer")
703
704         col = split.column()
705         col.prop(rd, "dither_intensity", text="Dither", slider=True)
706
707
708 class CYCLES_CAMERA_PT_dof(CyclesButtonsPanel, Panel):
709     bl_label = "Depth of Field"
710     bl_context = "data"
711
712     @classmethod
713     def poll(cls, context):
714         return context.camera and CyclesButtonsPanel.poll(context)
715
716     def draw(self, context):
717         layout = self.layout
718
719         cam = context.camera
720         ccam = cam.cycles
721         dof_options = cam.gpu_dof
722
723         split = layout.split()
724
725         col = split.column()
726         col.label("Focus:")
727         col.prop(cam, "dof_object", text="")
728
729         sub = col.row()
730         sub.active = cam.dof_object is None
731         sub.prop(cam, "dof_distance", text="Distance")
732
733         hq_support = dof_options.is_hq_supported
734         sub = col.column(align=True)
735         sub.label("Viewport:")
736         subhq = sub.column()
737         subhq.active = hq_support
738         subhq.prop(dof_options, "use_high_quality")
739         sub.prop(dof_options, "fstop")
740         if dof_options.use_high_quality and hq_support:
741             sub.prop(dof_options, "blades")
742
743         col = split.column()
744
745         col.label("Aperture:")
746         sub = col.column(align=True)
747         sub.prop(ccam, "aperture_type", text="")
748         if ccam.aperture_type == 'RADIUS':
749             sub.prop(ccam, "aperture_size", text="Size")
750         elif ccam.aperture_type == 'FSTOP':
751             sub.prop(ccam, "aperture_fstop", text="Number")
752
753         sub = col.column(align=True)
754         sub.prop(ccam, "aperture_blades", text="Blades")
755         sub.prop(ccam, "aperture_rotation", text="Rotation")
756         sub.prop(ccam, "aperture_ratio", text="Ratio")
757
758
759 class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
760     bl_label = ""
761     bl_context = "material"
762     bl_options = {'HIDE_HEADER'}
763
764     @classmethod
765     def poll(cls, context):
766         return (context.material or context.object) and CyclesButtonsPanel.poll(context)
767
768     def draw(self, context):
769         layout = self.layout
770
771         mat = context.material
772         ob = context.object
773         slot = context.material_slot
774         space = context.space_data
775
776         if ob:
777             is_sortable = len(ob.material_slots) > 1
778             rows = 1
779             if (is_sortable):
780                 rows = 4
781
782             row = layout.row()
783
784             row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows)
785
786             col = row.column(align=True)
787             col.operator("object.material_slot_add", icon='ZOOMIN', text="")
788             col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
789
790             col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
791
792             if is_sortable:
793                 col.separator()
794
795                 col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
796                 col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
797
798             if ob.mode == 'EDIT':
799                 row = layout.row(align=True)
800                 row.operator("object.material_slot_assign", text="Assign")
801                 row.operator("object.material_slot_select", text="Select")
802                 row.operator("object.material_slot_deselect", text="Deselect")
803
804         split = layout.split(percentage=0.65)
805
806         if ob:
807             split.template_ID(ob, "active_material", new="material.new")
808             row = split.row()
809
810             if slot:
811                 row.prop(slot, "link", text="")
812             else:
813                 row.label()
814         elif mat:
815             split.template_ID(space, "pin_id")
816             split.separator()
817
818
819 class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
820     bl_label = "Motion Blur"
821     bl_context = "object"
822     bl_options = {'DEFAULT_CLOSED'}
823
824     @classmethod
825     def poll(cls, context):
826         ob = context.object
827         if CyclesButtonsPanel.poll(context) and ob:
828             if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA'}:
829                 return True
830             if ob.dupli_type == 'GROUP' and ob.dupli_group:
831                 return True
832             # TODO(sergey): More duplicator types here?
833         return False
834
835     def draw_header(self, context):
836         layout = self.layout
837
838         rd = context.scene.render
839         # scene = context.scene
840
841         layout.active = rd.use_motion_blur
842
843         ob = context.object
844         cob = ob.cycles
845
846         layout.prop(cob, "use_motion_blur", text="")
847
848     def draw(self, context):
849         layout = self.layout
850
851         rd = context.scene.render
852         # scene = context.scene
853
854         ob = context.object
855         cob = ob.cycles
856
857         layout.active = (rd.use_motion_blur and cob.use_motion_blur)
858
859         row = layout.row()
860         if ob.type != 'CAMERA':
861             row.prop(cob, "use_deform_motion", text="Deformation")
862         row.prop(cob, "motion_steps", text="Steps")
863
864
865 class CYCLES_OBJECT_PT_cycles_settings(CyclesButtonsPanel, Panel):
866     bl_label = "Cycles Settings"
867     bl_context = "object"
868     bl_options = {'DEFAULT_CLOSED'}
869
870     @classmethod
871     def poll(cls, context):
872         ob = context.object
873         return (CyclesButtonsPanel.poll(context) and
874                 ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LAMP'}) or
875                         (ob.dupli_type == 'GROUP' and ob.dupli_group)))
876
877     def draw(self, context):
878         layout = self.layout
879
880         scene = context.scene
881         cscene = scene.cycles
882         ob = context.object
883         cob = ob.cycles
884         visibility = ob.cycles_visibility
885
886         layout.label(text="Ray Visibility:")
887         flow = layout.column_flow()
888
889         flow.prop(visibility, "camera")
890         flow.prop(visibility, "diffuse")
891         flow.prop(visibility, "glossy")
892         flow.prop(visibility, "transmission")
893         flow.prop(visibility, "scatter")
894
895         if ob.type != 'LAMP':
896             flow.prop(visibility, "shadow")
897
898         row = layout.row()
899         row.prop(cob, "is_shadow_catcher")
900         row.prop(cob, "is_holdout")
901
902         col = layout.column()
903         col.label(text="Performance:")
904         row = col.row()
905         sub = row.row()
906         sub.active = scene.render.use_simplify and cscene.use_camera_cull
907         sub.prop(cob, "use_camera_cull")
908
909         sub = row.row()
910         sub.active = scene.render.use_simplify and cscene.use_distance_cull
911         sub.prop(cob, "use_distance_cull")
912
913
914 def find_node(material, nodetype):
915     if material and material.node_tree:
916         ntree = material.node_tree
917
918         active_output_node = None
919         for node in ntree.nodes:
920             if getattr(node, "type", None) == nodetype:
921                 if getattr(node, "is_active_output", True):
922                     return node
923                 if not active_output_node:
924                     active_output_node = node
925         return active_output_node
926
927     return None
928
929
930 def find_node_input(node, name):
931     for input in node.inputs:
932         if input.name == name:
933             return input
934
935     return None
936
937
938 def panel_node_draw(layout, id_data, output_type, input_name):
939     if not id_data.use_nodes:
940         layout.operator("cycles.use_shading_nodes", icon='NODETREE')
941         return False
942
943     ntree = id_data.node_tree
944
945     node = find_node(id_data, output_type)
946     if not node:
947         layout.label(text="No output node")
948     else:
949         input = find_node_input(node, input_name)
950         layout.template_node_view(ntree, node, input)
951
952     return True
953
954
955 class CYCLES_LAMP_PT_preview(CyclesButtonsPanel, Panel):
956     bl_label = "Preview"
957     bl_context = "data"
958     bl_options = {'DEFAULT_CLOSED'}
959
960     @classmethod
961     def poll(cls, context):
962         return context.lamp and \
963             not (context.lamp.type == 'AREA' and
964                  context.lamp.cycles.is_portal) \
965             and CyclesButtonsPanel.poll(context)
966
967     def draw(self, context):
968         self.layout.template_preview(context.lamp)
969
970
971 class CYCLES_LAMP_PT_lamp(CyclesButtonsPanel, Panel):
972     bl_label = "Lamp"
973     bl_context = "data"
974
975     @classmethod
976     def poll(cls, context):
977         return context.lamp and CyclesButtonsPanel.poll(context)
978
979     def draw(self, context):
980         layout = self.layout
981
982         lamp = context.lamp
983         clamp = lamp.cycles
984         # cscene = context.scene.cycles
985
986         layout.prop(lamp, "type", expand=True)
987
988         split = layout.split()
989         col = split.column(align=True)
990
991         if lamp.type in {'POINT', 'SUN', 'SPOT'}:
992             col.prop(lamp, "shadow_soft_size", text="Size")
993         elif lamp.type == 'AREA':
994             col.prop(lamp, "shape", text="")
995             sub = col.column(align=True)
996
997             if lamp.shape == 'SQUARE':
998                 sub.prop(lamp, "size")
999             elif lamp.shape == 'RECTANGLE':
1000                 sub.prop(lamp, "size", text="Size X")
1001                 sub.prop(lamp, "size_y", text="Size Y")
1002
1003         if not (lamp.type == 'AREA' and clamp.is_portal):
1004             sub = col.column(align=True)
1005             if use_branched_path(context):
1006                 subsub = sub.row(align=True)
1007                 subsub.active = use_sample_all_lights(context)
1008                 subsub.prop(clamp, "samples")
1009             sub.prop(clamp, "max_bounces")
1010
1011         col = split.column()
1012
1013         sub = col.column(align=True)
1014         sub.active = not (lamp.type == 'AREA' and clamp.is_portal)
1015         sub.prop(clamp, "cast_shadow")
1016         sub.prop(clamp, "use_multiple_importance_sampling", text="Multiple Importance")
1017
1018         if lamp.type == 'AREA':
1019             col.prop(clamp, "is_portal", text="Portal")
1020
1021         if lamp.type == 'HEMI':
1022             layout.label(text="Not supported, interpreted as sun lamp")
1023
1024
1025 class CYCLES_LAMP_PT_nodes(CyclesButtonsPanel, Panel):
1026     bl_label = "Nodes"
1027     bl_context = "data"
1028
1029     @classmethod
1030     def poll(cls, context):
1031         return context.lamp and not (context.lamp.type == 'AREA' and
1032                                      context.lamp.cycles.is_portal) and \
1033             CyclesButtonsPanel.poll(context)
1034
1035     def draw(self, context):
1036         layout = self.layout
1037
1038         lamp = context.lamp
1039         if not panel_node_draw(layout, lamp, 'OUTPUT_LAMP', 'Surface'):
1040             layout.prop(lamp, "color")
1041
1042
1043 class CYCLES_LAMP_PT_spot(CyclesButtonsPanel, Panel):
1044     bl_label = "Spot Shape"
1045     bl_context = "data"
1046
1047     @classmethod
1048     def poll(cls, context):
1049         lamp = context.lamp
1050         return (lamp and lamp.type == 'SPOT') and CyclesButtonsPanel.poll(context)
1051
1052     def draw(self, context):
1053         layout = self.layout
1054
1055         lamp = context.lamp
1056
1057         split = layout.split()
1058
1059         col = split.column()
1060         sub = col.column()
1061         sub.prop(lamp, "spot_size", text="Size")
1062         sub.prop(lamp, "spot_blend", text="Blend", slider=True)
1063
1064         col = split.column()
1065         col.prop(lamp, "show_cone")
1066
1067
1068 class CYCLES_WORLD_PT_preview(CyclesButtonsPanel, Panel):
1069     bl_label = "Preview"
1070     bl_context = "world"
1071     bl_options = {'DEFAULT_CLOSED'}
1072
1073     @classmethod
1074     def poll(cls, context):
1075         return context.world and CyclesButtonsPanel.poll(context)
1076
1077     def draw(self, context):
1078         self.layout.template_preview(context.world)
1079
1080
1081 class CYCLES_WORLD_PT_surface(CyclesButtonsPanel, Panel):
1082     bl_label = "Surface"
1083     bl_context = "world"
1084
1085     @classmethod
1086     def poll(cls, context):
1087         return context.world and CyclesButtonsPanel.poll(context)
1088
1089     def draw(self, context):
1090         layout = self.layout
1091
1092         world = context.world
1093
1094         if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
1095             layout.prop(world, "horizon_color", text="Color")
1096
1097
1098 class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel):
1099     bl_label = "Volume"
1100     bl_context = "world"
1101     bl_options = {'DEFAULT_CLOSED'}
1102
1103     @classmethod
1104     def poll(cls, context):
1105         world = context.world
1106         return world and world.node_tree and CyclesButtonsPanel.poll(context)
1107
1108     def draw(self, context):
1109         layout = self.layout
1110
1111         world = context.world
1112         panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
1113
1114
1115 class CYCLES_WORLD_PT_ambient_occlusion(CyclesButtonsPanel, Panel):
1116     bl_label = "Ambient Occlusion"
1117     bl_context = "world"
1118
1119     @classmethod
1120     def poll(cls, context):
1121         return context.world and CyclesButtonsPanel.poll(context)
1122
1123     def draw_header(self, context):
1124         light = context.world.light_settings
1125         self.layout.prop(light, "use_ambient_occlusion", text="")
1126
1127     def draw(self, context):
1128         layout = self.layout
1129
1130         light = context.world.light_settings
1131         scene = context.scene
1132
1133         row = layout.row()
1134         sub = row.row()
1135         sub.active = light.use_ambient_occlusion or scene.render.use_simplify
1136         sub.prop(light, "ao_factor", text="Factor")
1137         row.prop(light, "distance", text="Distance")
1138
1139
1140 class CYCLES_WORLD_PT_mist(CyclesButtonsPanel, Panel):
1141     bl_label = "Mist Pass"
1142     bl_context = "world"
1143     bl_options = {'DEFAULT_CLOSED'}
1144
1145     @classmethod
1146     def poll(cls, context):
1147         if CyclesButtonsPanel.poll(context):
1148             if context.world:
1149                 for rl in context.scene.render.layers:
1150                     if rl.use_pass_mist:
1151                         return True
1152
1153         return False
1154
1155     def draw(self, context):
1156         layout = self.layout
1157
1158         world = context.world
1159
1160         split = layout.split(align=True)
1161         split.prop(world.mist_settings, "start")
1162         split.prop(world.mist_settings, "depth")
1163
1164         layout.prop(world.mist_settings, "falloff")
1165
1166
1167 class CYCLES_WORLD_PT_ray_visibility(CyclesButtonsPanel, Panel):
1168     bl_label = "Ray Visibility"
1169     bl_context = "world"
1170     bl_options = {'DEFAULT_CLOSED'}
1171
1172     @classmethod
1173     def poll(cls, context):
1174         return CyclesButtonsPanel.poll(context) and context.world
1175
1176     def draw(self, context):
1177         layout = self.layout
1178
1179         world = context.world
1180         visibility = world.cycles_visibility
1181
1182         flow = layout.column_flow()
1183
1184         flow.prop(visibility, "camera")
1185         flow.prop(visibility, "diffuse")
1186         flow.prop(visibility, "glossy")
1187         flow.prop(visibility, "transmission")
1188         flow.prop(visibility, "scatter")
1189
1190
1191 class CYCLES_WORLD_PT_settings(CyclesButtonsPanel, Panel):
1192     bl_label = "Settings"
1193     bl_context = "world"
1194     bl_options = {'DEFAULT_CLOSED'}
1195
1196     @classmethod
1197     def poll(cls, context):
1198         return context.world and CyclesButtonsPanel.poll(context)
1199
1200     def draw(self, context):
1201         layout = self.layout
1202
1203         world = context.world
1204         cworld = world.cycles
1205         # cscene = context.scene.cycles
1206
1207         split = layout.split()
1208
1209         col = split.column()
1210
1211         col.label(text="Surface:")
1212         col.prop(cworld, "sampling_method", text="Sampling")
1213
1214         sub = col.column(align=True)
1215         sub.active = cworld.sampling_method != 'NONE'
1216         subsub = sub.row(align=True)
1217         subsub.active = cworld.sampling_method == 'MANUAL'
1218         subsub.prop(cworld, "sample_map_resolution")
1219         if use_branched_path(context):
1220             subsub = sub.row(align=True)
1221             subsub.active = use_sample_all_lights(context)
1222             subsub.prop(cworld, "samples")
1223         sub.prop(cworld, "max_bounces")
1224
1225         col = split.column()
1226         col.label(text="Volume:")
1227         sub = col.column()
1228         sub.active = use_cpu(context)
1229         sub.prop(cworld, "volume_sampling", text="")
1230         col.prop(cworld, "volume_interpolation", text="")
1231         col.prop(cworld, "homogeneous_volume", text="Homogeneous")
1232
1233
1234 class CYCLES_MATERIAL_PT_preview(CyclesButtonsPanel, Panel):
1235     bl_label = "Preview"
1236     bl_context = "material"
1237     bl_options = {'DEFAULT_CLOSED'}
1238
1239     @classmethod
1240     def poll(cls, context):
1241         return context.material and CyclesButtonsPanel.poll(context)
1242
1243     def draw(self, context):
1244         self.layout.template_preview(context.material)
1245
1246
1247 class CYCLES_MATERIAL_PT_surface(CyclesButtonsPanel, Panel):
1248     bl_label = "Surface"
1249     bl_context = "material"
1250
1251     @classmethod
1252     def poll(cls, context):
1253         return context.material and CyclesButtonsPanel.poll(context)
1254
1255     def draw(self, context):
1256         layout = self.layout
1257
1258         mat = context.material
1259         if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'):
1260             layout.prop(mat, "diffuse_color")
1261
1262
1263 class CYCLES_MATERIAL_PT_volume(CyclesButtonsPanel, Panel):
1264     bl_label = "Volume"
1265     bl_context = "material"
1266     bl_options = {'DEFAULT_CLOSED'}
1267
1268     @classmethod
1269     def poll(cls, context):
1270         mat = context.material
1271         return mat and mat.node_tree and CyclesButtonsPanel.poll(context)
1272
1273     def draw(self, context):
1274         layout = self.layout
1275
1276         mat = context.material
1277         # cmat = mat.cycles
1278
1279         panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
1280
1281
1282 class CYCLES_MATERIAL_PT_displacement(CyclesButtonsPanel, Panel):
1283     bl_label = "Displacement"
1284     bl_context = "material"
1285
1286     @classmethod
1287     def poll(cls, context):
1288         mat = context.material
1289         return mat and mat.node_tree and CyclesButtonsPanel.poll(context)
1290
1291     def draw(self, context):
1292         layout = self.layout
1293
1294         mat = context.material
1295         panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
1296
1297
1298 class CYCLES_MATERIAL_PT_settings(CyclesButtonsPanel, Panel):
1299     bl_label = "Settings"
1300     bl_context = "material"
1301
1302     @classmethod
1303     def poll(cls, context):
1304         return context.material and CyclesButtonsPanel.poll(context)
1305
1306     def draw(self, context):
1307         layout = self.layout
1308
1309         mat = context.material
1310         cmat = mat.cycles
1311
1312         split = layout.split()
1313         col = split.column()
1314         col.label(text="Surface:")
1315         col.prop(cmat, "sample_as_light", text="Multiple Importance")
1316         col.prop(cmat, "use_transparent_shadow")
1317
1318         col.separator()
1319         col.label(text="Geometry:")
1320         col.prop(cmat, "displacement_method", text="")
1321
1322         col = split.column()
1323         col.label(text="Volume:")
1324         sub = col.column()
1325         sub.active = use_cpu(context)
1326         sub.prop(cmat, "volume_sampling", text="")
1327         col.prop(cmat, "volume_interpolation", text="")
1328         col.prop(cmat, "homogeneous_volume", text="Homogeneous")
1329
1330         col.separator()
1331         col.prop(mat, "pass_index")
1332
1333
1334 class CYCLES_MATERIAL_PT_viewport(CyclesButtonsPanel, Panel):
1335     bl_label = "Viewport"
1336     bl_context = "material"
1337     bl_options = {'DEFAULT_CLOSED'}
1338
1339     @classmethod
1340     def poll(cls, context):
1341         return context.material and CyclesButtonsPanel.poll(context)
1342
1343     def draw(self, context):
1344         mat = context.material
1345
1346         layout = self.layout
1347         split = layout.split()
1348
1349         col = split.column(align=True)
1350         col.label("Color:")
1351         col.prop(mat, "diffuse_color", text="")
1352         col.prop(mat, "alpha")
1353
1354         col.separator()
1355         col.label("Alpha:")
1356         col.prop(mat.game_settings, "alpha_blend", text="")
1357
1358         col = split.column(align=True)
1359         col.label("Specular:")
1360         col.prop(mat, "specular_color", text="")
1361         col.prop(mat, "specular_hardness", text="Hardness")
1362
1363
1364 class CYCLES_TEXTURE_PT_context(CyclesButtonsPanel, Panel):
1365     bl_label = ""
1366     bl_context = "texture"
1367     bl_options = {'HIDE_HEADER'}
1368     COMPAT_ENGINES = {'CYCLES'}
1369
1370     def draw(self, context):
1371         layout = self.layout
1372
1373         tex = context.texture
1374         space = context.space_data
1375         pin_id = space.pin_id
1376         use_pin_id = space.use_pin_id
1377         user = context.texture_user
1378
1379         space.use_limited_texture_context = False
1380
1381         if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)):
1382             pin_id = None
1383
1384         if not pin_id:
1385             layout.template_texture_user()
1386
1387         if user or pin_id:
1388             layout.separator()
1389
1390             split = layout.split(percentage=0.65)
1391             col = split.column()
1392
1393             if pin_id:
1394                 col.template_ID(space, "pin_id")
1395             else:
1396                 propname = context.texture_user_property.identifier
1397                 col.template_ID(user, propname, new="texture.new")
1398
1399             if tex:
1400                 split = layout.split(percentage=0.2)
1401                 split.label(text="Type:")
1402                 split.prop(tex, "type", text="")
1403
1404
1405 class CYCLES_TEXTURE_PT_node(CyclesButtonsPanel, Panel):
1406     bl_label = "Node"
1407     bl_context = "texture"
1408
1409     @classmethod
1410     def poll(cls, context):
1411         node = context.texture_node
1412         return node and CyclesButtonsPanel.poll(context)
1413
1414     def draw(self, context):
1415         layout = self.layout
1416
1417         node = context.texture_node
1418         ntree = node.id_data
1419         layout.template_node_view(ntree, node, None)
1420
1421
1422 class CYCLES_TEXTURE_PT_mapping(CyclesButtonsPanel, Panel):
1423     bl_label = "Mapping"
1424     bl_context = "texture"
1425
1426     @classmethod
1427     def poll(cls, context):
1428         node = context.texture_node
1429         # TODO(sergey): perform a faster/nicer check?
1430         return node and hasattr(node, 'texture_mapping') and CyclesButtonsPanel.poll(context)
1431
1432     def draw(self, context):
1433         layout = self.layout
1434
1435         node = context.texture_node
1436
1437         mapping = node.texture_mapping
1438
1439         layout.prop(mapping, "vector_type", expand=True)
1440
1441         row = layout.row()
1442
1443         row.column().prop(mapping, "translation")
1444         row.column().prop(mapping, "rotation")
1445         row.column().prop(mapping, "scale")
1446
1447         layout.label(text="Projection:")
1448
1449         row = layout.row()
1450         row.prop(mapping, "mapping_x", text="")
1451         row.prop(mapping, "mapping_y", text="")
1452         row.prop(mapping, "mapping_z", text="")
1453
1454
1455 class CYCLES_TEXTURE_PT_colors(CyclesButtonsPanel, Panel):
1456     bl_label = "Color"
1457     bl_context = "texture"
1458     bl_options = {'DEFAULT_CLOSED'}
1459
1460     @classmethod
1461     def poll(cls, context):
1462         # node = context.texture_node
1463         return False
1464         # return node and CyclesButtonsPanel.poll(context)
1465
1466     def draw(self, context):
1467         layout = self.layout
1468
1469         node = context.texture_node
1470
1471         mapping = node.color_mapping
1472
1473         split = layout.split()
1474
1475         col = split.column()
1476         col.label(text="Blend:")
1477         col.prop(mapping, "blend_type", text="")
1478         col.prop(mapping, "blend_factor", text="Factor")
1479         col.prop(mapping, "blend_color", text="")
1480
1481         col = split.column()
1482         col.label(text="Adjust:")
1483         col.prop(mapping, "brightness")
1484         col.prop(mapping, "contrast")
1485         col.prop(mapping, "saturation")
1486
1487         layout.separator()
1488
1489         layout.prop(mapping, "use_color_ramp", text="Ramp")
1490         if mapping.use_color_ramp:
1491             layout.template_color_ramp(mapping, "color_ramp", expand=True)
1492
1493
1494 class CYCLES_PARTICLE_PT_textures(CyclesButtonsPanel, Panel):
1495     bl_label = "Textures"
1496     bl_context = "particle"
1497     bl_options = {'DEFAULT_CLOSED'}
1498
1499     @classmethod
1500     def poll(cls, context):
1501         psys = context.particle_system
1502         return psys and CyclesButtonsPanel.poll(context)
1503
1504     def draw(self, context):
1505         layout = self.layout
1506
1507         psys = context.particle_system
1508         part = psys.settings
1509
1510         row = layout.row()
1511         row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2)
1512
1513         col = row.column(align=True)
1514         col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
1515         col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
1516         col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="")
1517
1518         if not part.active_texture:
1519             layout.template_ID(part, "active_texture", new="texture.new")
1520         else:
1521             slot = part.texture_slots[part.active_texture_index]
1522             layout.template_ID(slot, "texture", new="texture.new")
1523
1524
1525 class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel):
1526     bl_label = "Bake"
1527     bl_context = "render"
1528     bl_options = {'DEFAULT_CLOSED'}
1529     COMPAT_ENGINES = {'CYCLES'}
1530
1531     def draw(self, context):
1532         layout = self.layout
1533
1534         scene = context.scene
1535         cscene = scene.cycles
1536         cbk = scene.render.bake
1537
1538         layout.operator("object.bake", icon='RENDER_STILL').type = cscene.bake_type
1539
1540         col = layout.column()
1541         col.prop(cscene, "bake_type")
1542
1543         col = layout.column()
1544
1545         if cscene.bake_type == 'NORMAL':
1546             col.prop(cbk, "normal_space", text="Space")
1547
1548             row = col.row(align=True)
1549             row.label(text="Swizzle:")
1550             row.prop(cbk, "normal_r", text="")
1551             row.prop(cbk, "normal_g", text="")
1552             row.prop(cbk, "normal_b", text="")
1553
1554         elif cscene.bake_type == 'COMBINED':
1555             row = col.row(align=True)
1556             row.prop(cbk, "use_pass_direct", toggle=True)
1557             row.prop(cbk, "use_pass_indirect", toggle=True)
1558
1559             split = col.split()
1560             split.active = cbk.use_pass_direct or cbk.use_pass_indirect
1561
1562             col = split.column()
1563             col.prop(cbk, "use_pass_diffuse")
1564             col.prop(cbk, "use_pass_glossy")
1565             col.prop(cbk, "use_pass_transmission")
1566
1567             col = split.column()
1568             col.prop(cbk, "use_pass_subsurface")
1569             col.prop(cbk, "use_pass_ambient_occlusion")
1570             col.prop(cbk, "use_pass_emit")
1571
1572         elif cscene.bake_type in {'DIFFUSE', 'GLOSSY', 'TRANSMISSION', 'SUBSURFACE'}:
1573             row = col.row(align=True)
1574             row.prop(cbk, "use_pass_direct", toggle=True)
1575             row.prop(cbk, "use_pass_indirect", toggle=True)
1576             row.prop(cbk, "use_pass_color", toggle=True)
1577
1578         layout.separator()
1579
1580         split = layout.split()
1581
1582         col = split.column()
1583         col.prop(cbk, "margin")
1584         col.prop(cbk, "use_clear")
1585
1586         col = split.column()
1587         col.prop(cbk, "use_selected_to_active")
1588         sub = col.column()
1589         sub.active = cbk.use_selected_to_active
1590         sub.prop(cbk, "use_cage", text="Cage")
1591         if cbk.use_cage:
1592             sub.prop(cbk, "cage_extrusion", text="Extrusion")
1593             sub.prop_search(cbk, "cage_object", scene, "objects", text="")
1594         else:
1595             sub.prop(cbk, "cage_extrusion", text="Ray Distance")
1596
1597
1598 class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel):
1599     bl_label = "Debug"
1600     bl_context = "render"
1601     bl_options = {'DEFAULT_CLOSED'}
1602     COMPAT_ENGINES = {'CYCLES'}
1603
1604     @classmethod
1605     def poll(cls, context):
1606         return CyclesButtonsPanel.poll(context) and bpy.app.debug_value == 256
1607
1608     def draw(self, context):
1609         layout = self.layout
1610
1611         scene = context.scene
1612         cscene = scene.cycles
1613
1614         col = layout.column()
1615
1616         col.label('CPU Flags:')
1617         row = col.row(align=True)
1618         row.prop(cscene, "debug_use_cpu_sse2", toggle=True)
1619         row.prop(cscene, "debug_use_cpu_sse3", toggle=True)
1620         row.prop(cscene, "debug_use_cpu_sse41", toggle=True)
1621         row.prop(cscene, "debug_use_cpu_avx", toggle=True)
1622         row.prop(cscene, "debug_use_cpu_avx2", toggle=True)
1623         col.prop(cscene, "debug_bvh_layout")
1624         col.prop(cscene, "debug_use_cpu_split_kernel")
1625
1626         col.separator()
1627
1628         col = layout.column()
1629         col.label('CUDA Flags:')
1630         col.prop(cscene, "debug_use_cuda_adaptive_compile")
1631         col.prop(cscene, "debug_use_cuda_split_kernel")
1632
1633         col.separator()
1634
1635         col = layout.column()
1636         col.label('OpenCL Flags:')
1637         col.prop(cscene, "debug_opencl_kernel_type", text="Kernel")
1638         col.prop(cscene, "debug_opencl_device_type", text="Device")
1639         col.prop(cscene, "debug_opencl_kernel_single_program", text="Single Program")
1640         col.prop(cscene, "debug_use_opencl_debug", text="Debug")
1641         col.prop(cscene, "debug_opencl_mem_limit")
1642
1643         col.separator()
1644
1645         col = layout.column()
1646         col.prop(cscene, "debug_bvh_type")
1647
1648
1649 class CYCLES_PARTICLE_PT_curve_settings(CyclesButtonsPanel, Panel):
1650     bl_label = "Cycles Hair Settings"
1651     bl_context = "particle"
1652
1653     @classmethod
1654     def poll(cls, context):
1655         scene = context.scene
1656         ccscene = scene.cycles_curves
1657         psys = context.particle_system
1658         use_curves = ccscene.use_curves and psys
1659         return CyclesButtonsPanel.poll(context) and use_curves and psys.settings.type == 'HAIR'
1660
1661     def draw(self, context):
1662         layout = self.layout
1663
1664         psys = context.particle_settings
1665         cpsys = psys.cycles
1666
1667         row = layout.row()
1668         row.prop(cpsys, "shape", text="Shape")
1669
1670         layout.label(text="Thickness:")
1671         row = layout.row()
1672         row.prop(cpsys, "root_width", text="Root")
1673         row.prop(cpsys, "tip_width", text="Tip")
1674
1675         row = layout.row()
1676         row.prop(cpsys, "radius_scale", text="Scaling")
1677         row.prop(cpsys, "use_closetip", text="Close tip")
1678
1679
1680 class CYCLES_SCENE_PT_simplify(CyclesButtonsPanel, Panel):
1681     bl_label = "Simplify"
1682     bl_context = "scene"
1683     COMPAT_ENGINES = {'CYCLES'}
1684
1685     def draw_header(self, context):
1686         rd = context.scene.render
1687         self.layout.prop(rd, "use_simplify", text="")
1688
1689     def draw(self, context):
1690         layout = self.layout
1691
1692         scene = context.scene
1693         rd = scene.render
1694         cscene = scene.cycles
1695
1696         layout.active = rd.use_simplify
1697
1698         col = layout.column(align=True)
1699         col.label(text="Subdivision")
1700         row = col.row(align=True)
1701         row.prop(rd, "simplify_subdivision", text="Viewport")
1702         row.prop(rd, "simplify_subdivision_render", text="Render")
1703
1704         col = layout.column(align=True)
1705         col.label(text="Child Particles")
1706         row = col.row(align=True)
1707         row.prop(rd, "simplify_child_particles", text="Viewport")
1708         row.prop(rd, "simplify_child_particles_render", text="Render")
1709
1710         col = layout.column(align=True)
1711         split = col.split()
1712         sub = split.column()
1713         sub.label(text="Texture Limit Viewport")
1714         sub.prop(cscene, "texture_limit", text="")
1715         sub = split.column()
1716         sub.label(text="Texture Limit Render")
1717         sub.prop(cscene, "texture_limit_render", text="")
1718
1719         split = layout.split()
1720         col = split.column()
1721         col.prop(cscene, "use_camera_cull")
1722         row = col.row()
1723         row.active = cscene.use_camera_cull
1724         row.prop(cscene, "camera_cull_margin")
1725
1726         col = split.column()
1727         col.prop(cscene, "use_distance_cull")
1728         row = col.row()
1729         row.active = cscene.use_distance_cull
1730         row.prop(cscene, "distance_cull_margin", text="Distance")
1731
1732         split = layout.split()
1733         col = split.column()
1734         col.prop(cscene, "ao_bounces")
1735
1736         col = split.column()
1737         col.prop(cscene, "ao_bounces_render")
1738
1739
1740 def draw_device(self, context):
1741     scene = context.scene
1742     layout = self.layout
1743
1744     if scene.render.engine == 'CYCLES':
1745         from . import engine
1746         cscene = scene.cycles
1747
1748         layout.prop(cscene, "feature_set")
1749
1750         split = layout.split(percentage=1 / 3)
1751         split.label("Device:")
1752         row = split.row()
1753         row.active = show_device_active(context)
1754         row.prop(cscene, "device", text="")
1755
1756         if engine.with_osl() and use_cpu(context):
1757             layout.prop(cscene, "shading_system")
1758
1759
1760 def draw_pause(self, context):
1761     layout = self.layout
1762     scene = context.scene
1763
1764     if scene.render.engine == "CYCLES":
1765         view = context.space_data
1766
1767         if view.viewport_shade == 'RENDERED':
1768             cscene = scene.cycles
1769             layername = scene.render.layers.active.name
1770             layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
1771             layout.prop(cscene, "preview_active_layer", icon="RENDERLAYERS", text=layername)
1772
1773
1774 def get_panels():
1775     exclude_panels = {
1776         'DATA_PT_area',
1777         'DATA_PT_camera_dof',
1778         'DATA_PT_falloff_curve',
1779         'DATA_PT_lamp',
1780         'DATA_PT_preview',
1781         'DATA_PT_shadow',
1782         'DATA_PT_spot',
1783         'DATA_PT_sunsky',
1784         'MATERIAL_PT_context_material',
1785         'MATERIAL_PT_diffuse',
1786         'MATERIAL_PT_flare',
1787         'MATERIAL_PT_halo',
1788         'MATERIAL_PT_mirror',
1789         'MATERIAL_PT_options',
1790         'MATERIAL_PT_pipeline',
1791         'MATERIAL_PT_preview',
1792         'MATERIAL_PT_shading',
1793         'MATERIAL_PT_shadow',
1794         'MATERIAL_PT_specular',
1795         'MATERIAL_PT_sss',
1796         'MATERIAL_PT_strand',
1797         'MATERIAL_PT_transp',
1798         'MATERIAL_PT_volume_density',
1799         'MATERIAL_PT_volume_integration',
1800         'MATERIAL_PT_volume_lighting',
1801         'MATERIAL_PT_volume_options',
1802         'MATERIAL_PT_volume_shading',
1803         'MATERIAL_PT_volume_transp',
1804         'RENDERLAYER_PT_layer_options',
1805         'RENDERLAYER_PT_layer_passes',
1806         'RENDERLAYER_PT_views',
1807         'RENDER_PT_antialiasing',
1808         'RENDER_PT_bake',
1809         'RENDER_PT_motion_blur',
1810         'RENDER_PT_performance',
1811         'RENDER_PT_post_processing',
1812         'RENDER_PT_shading',
1813         'SCENE_PT_simplify',
1814         'TEXTURE_PT_context_texture',
1815         'WORLD_PT_ambient_occlusion',
1816         'WORLD_PT_environment_lighting',
1817         'WORLD_PT_gather',
1818         'WORLD_PT_indirect_lighting',
1819         'WORLD_PT_mist',
1820         'WORLD_PT_preview',
1821         'WORLD_PT_world'
1822     }
1823
1824     panels = []
1825     for panel in bpy.types.Panel.__subclasses__():
1826         if hasattr(panel, 'COMPAT_ENGINES') and 'BLENDER_RENDER' in panel.COMPAT_ENGINES:
1827             if panel.__name__ not in exclude_panels:
1828                 panels.append(panel)
1829
1830     return panels
1831
1832
1833 classes = (
1834     CYCLES_MT_sampling_presets,
1835     CYCLES_MT_integrator_presets,
1836     CYCLES_RENDER_PT_sampling,
1837     CYCLES_RENDER_PT_geometry,
1838     CYCLES_RENDER_PT_light_paths,
1839     CYCLES_RENDER_PT_motion_blur,
1840     CYCLES_RENDER_PT_film,
1841     CYCLES_RENDER_PT_performance,
1842     CYCLES_RENDER_PT_layer_options,
1843     CYCLES_RENDER_PT_layer_passes,
1844     CYCLES_RENDER_PT_views,
1845     CYCLES_RENDER_PT_denoising,
1846     CYCLES_PT_post_processing,
1847     CYCLES_CAMERA_PT_dof,
1848     CYCLES_PT_context_material,
1849     CYCLES_OBJECT_PT_motion_blur,
1850     CYCLES_OBJECT_PT_cycles_settings,
1851     CYCLES_LAMP_PT_preview,
1852     CYCLES_LAMP_PT_lamp,
1853     CYCLES_LAMP_PT_nodes,
1854     CYCLES_LAMP_PT_spot,
1855     CYCLES_WORLD_PT_preview,
1856     CYCLES_WORLD_PT_surface,
1857     CYCLES_WORLD_PT_volume,
1858     CYCLES_WORLD_PT_ambient_occlusion,
1859     CYCLES_WORLD_PT_mist,
1860     CYCLES_WORLD_PT_ray_visibility,
1861     CYCLES_WORLD_PT_settings,
1862     CYCLES_MATERIAL_PT_preview,
1863     CYCLES_MATERIAL_PT_surface,
1864     CYCLES_MATERIAL_PT_volume,
1865     CYCLES_MATERIAL_PT_displacement,
1866     CYCLES_MATERIAL_PT_settings,
1867     CYCLES_MATERIAL_PT_viewport,
1868     CYCLES_TEXTURE_PT_context,
1869     CYCLES_TEXTURE_PT_node,
1870     CYCLES_TEXTURE_PT_mapping,
1871     CYCLES_TEXTURE_PT_colors,
1872     CYCLES_PARTICLE_PT_textures,
1873     CYCLES_RENDER_PT_bake,
1874     CYCLES_RENDER_PT_debug,
1875     CYCLES_PARTICLE_PT_curve_settings,
1876     CYCLES_SCENE_PT_simplify,
1877 )
1878
1879
1880 def register():
1881     from bpy.utils import register_class
1882
1883     bpy.types.RENDER_PT_render.append(draw_device)
1884     bpy.types.VIEW3D_HT_header.append(draw_pause)
1885
1886     for panel in get_panels():
1887         panel.COMPAT_ENGINES.add('CYCLES')
1888
1889     for cls in classes:
1890         register_class(cls)
1891
1892
1893 def unregister():
1894     from bpy.utils import unregister_class
1895
1896     bpy.types.RENDER_PT_render.remove(draw_device)
1897     bpy.types.VIEW3D_HT_header.remove(draw_pause)
1898
1899     for panel in get_panels():
1900         if 'CYCLES' in panel.COMPAT_ENGINES:
1901             panel.COMPAT_ENGINES.remove('CYCLES')
1902
1903     for cls in classes:
1904         unregister_class(cls)