f3ed3b677fb5f35055181c615aef2e4b16781cdd
[blender.git] / intern / cycles / blender / addon / ui.py
1 #
2 # Copyright 2011, Blender Foundation.
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 #
18
19 # <pep8 compliant>
20
21 import bpy
22
23 from bpy.types import Panel, Menu
24
25 from cycles import enums
26 from cycles import engine
27
28
29 class CYCLES_MT_integrator_presets(Menu):
30     bl_label = "Integrator Presets"
31     preset_subdir = "cycles/integrator"
32     preset_operator = "script.execute_preset"
33     COMPAT_ENGINES = {'CYCLES'}
34     draw = Menu.draw_preset
35
36
37 class CyclesButtonsPanel():
38     bl_space_type = "PROPERTIES"
39     bl_region_type = "WINDOW"
40     bl_context = "render"
41
42     @classmethod
43     def poll(cls, context):
44         rd = context.scene.render
45         return rd.engine == 'CYCLES'
46
47
48 class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
49     bl_label = "Integrator"
50     bl_options = {'DEFAULT_CLOSED'}
51
52     def draw(self, context):
53         layout = self.layout
54
55         scene = context.scene
56         cscene = scene.cycles
57
58         row = layout.row(align=True)
59         row.menu("CYCLES_MT_integrator_presets", text=bpy.types.CYCLES_MT_integrator_presets.bl_label)
60         row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMIN")
61         row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMOUT").remove_active = True
62
63         split = layout.split()
64
65         col = split.column()
66         sub = col.column(align=True)
67         sub.label(text="Samples:")
68         sub.prop(cscene, "samples", text="Render")
69         sub.prop(cscene, "preview_samples", text="Preview")
70         sub.prop(cscene, "seed")
71
72         sub = col.column(align=True)
73         sub.label("Transparency:")
74         sub.prop(cscene, "transparent_max_bounces", text="Max")
75         sub.prop(cscene, "transparent_min_bounces", text="Min")
76         sub.prop(cscene, "use_transparent_shadows", text="Shadows")
77
78         col = split.column()
79
80         sub = col.column(align=True)
81         sub.label(text="Bounces:")
82         sub.prop(cscene, "max_bounces", text="Max")
83         sub.prop(cscene, "min_bounces", text="Min")
84
85         sub = col.column(align=True)
86         sub.label(text="Light Paths:")
87         sub.prop(cscene, "diffuse_bounces", text="Diffuse")
88         sub.prop(cscene, "glossy_bounces", text="Glossy")
89         sub.prop(cscene, "transmission_bounces", text="Transmission")
90         sub.prop(cscene, "no_caustics")
91
92         #row = col.row()
93         #row.prop(cscene, "blur_caustics")
94         #row.active = not cscene.no_caustics
95
96
97 class CyclesRender_PT_film(CyclesButtonsPanel, Panel):
98     bl_label = "Film"
99
100     def draw(self, context):
101         layout = self.layout
102
103         scene = context.scene
104         cscene = scene.cycles
105
106         split = layout.split()
107
108         col = split.column()
109         col.prop(cscene, "film_exposure")
110         col.prop(cscene, "film_transparent")
111
112         col = split.column()
113         sub = col.column(align=True)
114         sub.prop(cscene, "filter_type", text="")
115         if cscene.filter_type != 'BOX':
116             sub.prop(cscene, "filter_width", text="Width")
117
118
119 class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
120     bl_label = "Performance"
121     bl_options = {'DEFAULT_CLOSED'}
122
123     def draw(self, context):
124         layout = self.layout
125
126         scene = context.scene
127         rd = scene.render
128         cscene = scene.cycles
129
130         split = layout.split()
131
132         col = split.column(align=True)
133
134         col.label(text="Threads:")
135         col.row().prop(rd, "threads_mode", expand=True)
136         sub = col.column()
137         sub.enabled = rd.threads_mode == 'FIXED'
138         sub.prop(rd, "threads")
139
140         sub = col.column(align=True)
141         sub.label(text="Tiles:")
142         sub.prop(cscene, "debug_tile_size")
143         sub.prop(cscene, "debug_min_size")
144
145         col = split.column()
146
147         sub = col.column(align=True)
148         sub.label(text="Acceleration structure:")
149         sub.prop(cscene, "debug_bvh_type", text="")
150         sub.prop(cscene, "debug_use_spatial_splits")
151
152
153 class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
154     bl_label = "Layers"
155     bl_options = {'DEFAULT_CLOSED'}
156     COMPAT_ENGINES = {'BLENDER_RENDER'}
157
158     def draw(self, context):
159         layout = self.layout
160
161         scene = context.scene
162         rd = scene.render
163
164         # row = layout.row()
165         # row.template_list(rd, "layers", rd.layers, "active_index", rows=2)
166
167         # col = row.column(align=True)
168         # col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
169         # col.operator("scene.render_layer_remove", icon='ZOOMOUT', text="")
170
171         row = layout.row()
172         # rl = rd.layers.active
173         rl = rd.layers[0]
174         row.prop(rl, "name")
175         #row.prop(rd, "use_single_layer", text="", icon_only=True)
176
177         split = layout.split()
178
179         col = split.column()
180         col.prop(scene, "layers", text="Scene")
181
182         col = split.column()
183         col.prop(rl, "layers", text="Layer")
184
185         layout.separator()
186
187         layout.prop(rl, "material_override", text="Material")
188
189
190 class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
191     bl_label = "Post Processing"
192     bl_options = {'DEFAULT_CLOSED'}
193
194     def draw(self, context):
195         layout = self.layout
196
197         rd = context.scene.render
198
199         split = layout.split()
200
201         col = split.column()
202         col.prop(rd, "use_compositing")
203         col.prop(rd, "use_sequencer")
204
205         col = split.column()
206         col.prop(rd, "dither_intensity", text="Dither", slider=True)
207
208
209 class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel):
210     bl_label = "Depth of Field"
211     bl_context = "data"
212
213     @classmethod
214     def poll(cls, context):
215         return context.camera and CyclesButtonsPanel.poll(context)
216
217     def draw(self, context):
218         layout = self.layout
219
220         cam = context.camera
221         ccam = cam.cycles
222
223         split = layout.split()
224
225         col = split.column()
226         col.label("Focus:")
227         col.prop(cam, "dof_object", text="")
228
229         sub = col.row()
230         sub.active = cam.dof_object is None
231         sub.prop(cam, "dof_distance", text="Distance")
232
233         col = split.column()
234
235         col.label("Aperture:")
236         col.prop(ccam, "aperture_size", text="Size")
237
238         sub = col.column(align=True)
239         sub.prop(ccam, "aperture_blades", text="Blades")
240         sub.prop(ccam, "aperture_rotation", text="Rotation")
241
242
243 class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
244     bl_label = "Surface"
245     bl_context = "material"
246     bl_options = {'HIDE_HEADER'}
247
248     @classmethod
249     def poll(cls, context):
250         return (context.material or context.object) and CyclesButtonsPanel.poll(context)
251
252     def draw(self, context):
253         layout = self.layout
254
255         mat = context.material
256         ob = context.object
257         slot = context.material_slot
258         space = context.space_data
259
260         if ob:
261             row = layout.row()
262
263             row.template_list(ob, "material_slots", ob, "active_material_index", rows=2)
264
265             col = row.column(align=True)
266             col.operator("object.material_slot_add", icon='ZOOMIN', text="")
267             col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
268
269             col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
270
271             if ob.mode == 'EDIT':
272                 row = layout.row(align=True)
273                 row.operator("object.material_slot_assign", text="Assign")
274                 row.operator("object.material_slot_select", text="Select")
275                 row.operator("object.material_slot_deselect", text="Deselect")
276
277         split = layout.split(percentage=0.65)
278
279         if ob:
280             split.template_ID(ob, "active_material", new="material.new")
281             row = split.row()
282
283             if slot:
284                 row.prop(slot, "link", text="")
285             else:
286                 row.label()
287         elif mat:
288             split.template_ID(space, "pin_id")
289             split.separator()
290
291
292 class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
293     bl_label = "Displacement"
294     bl_context = "data"
295
296     @classmethod
297     def poll(cls, context):
298         return CyclesButtonsPanel.poll(context) and (context.mesh or context.curve or context.meta_ball)
299
300     def draw(self, context):
301         layout = self.layout
302
303         mesh = context.mesh
304         curve = context.curve
305         mball = context.meta_ball
306
307         if mesh:
308             cdata = mesh.cycles
309         elif curve:
310             cdata = curve.cycles
311         elif mball:
312             cdata = mball.cycles
313
314         layout.prop(cdata, "displacement_method", text="Method")
315         layout.prop(cdata, "use_subdivision")
316         layout.prop(cdata, "dicing_rate")
317
318
319 class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
320     bl_label = "Ray Visibility"
321     bl_context = "object"
322     bl_options = {'DEFAULT_CLOSED'}
323
324     @classmethod
325     def poll(cls, context):
326         ob = context.object
327         return CyclesButtonsPanel.poll(context) and ob and ob.type in ('MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META')  # todo: 'LAMP'
328
329     def draw(self, context):
330         layout = self.layout
331
332         ob = context.object
333         visibility = ob.cycles_visibility
334
335         split = layout.split()
336
337         col = split.column()
338         col.prop(visibility, "camera")
339         col.prop(visibility, "diffuse")
340         col.prop(visibility, "glossy")
341
342         col = split.column()
343         col.prop(visibility, "transmission")
344         col.prop(visibility, "shadow")
345
346
347 def find_node(material, nodetype):
348     if material and material.node_tree:
349         ntree = material.node_tree
350
351         for node in ntree.nodes:
352             if hasattr(node, 'type') and node.type == nodetype:
353                 return node
354
355     return None
356
357
358 def find_node_input(node, name):
359     for input in node.inputs:
360         if input.name == name:
361             return input
362
363     return None
364
365
366 def panel_node_draw(layout, id, output_type, input_name):
367     if not id.node_tree:
368         layout.prop(id, "use_nodes", icon='NODETREE')
369         return False
370
371     ntree = id.node_tree
372
373     node = find_node(id, output_type)
374     if not node:
375         layout.label(text="No output node.")
376     else:
377         input = find_node_input(node, input_name)
378         layout.template_node_view(ntree, node, input)
379
380     return True
381
382
383 class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
384     bl_label = "Lamp"
385     bl_context = "data"
386
387     @classmethod
388     def poll(cls, context):
389         return context.lamp and CyclesButtonsPanel.poll(context)
390
391     def draw(self, context):
392         layout = self.layout
393
394         lamp = context.lamp
395         clamp = lamp.cycles
396
397         layout.prop(lamp, "type", expand=True)
398
399         split = layout.split()
400         col = split.column(align=True)
401
402         if lamp.type in ('POINT', 'SUN', 'SPOT'):
403             col.prop(lamp, "shadow_soft_size", text="Size")
404         elif lamp.type == 'AREA':
405             col.prop(lamp, "shape", text="")
406             sub = col.column(align=True)
407
408             if lamp.shape == 'SQUARE':
409                 sub.prop(lamp, "size")
410             elif lamp.shape == 'RECTANGLE':
411                 sub.prop(lamp, "size", text="Size X")
412                 sub.prop(lamp, "size_y", text="Size Y")
413
414         col = split.column()
415         col.prop(clamp, "cast_shadow")
416
417         if lamp.type == 'SPOT':
418             layout.label(text="Not supported, interpreted as point lamp.")
419         elif lamp.type == 'HEMI':
420             layout.label(text="Not supported, interpreted as sun lamp.")
421
422
423 class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
424     bl_label = "Nodes"
425     bl_context = "data"
426
427     @classmethod
428     def poll(cls, context):
429         return context.lamp and CyclesButtonsPanel.poll(context)
430
431     def draw(self, context):
432         layout = self.layout
433
434         lamp = context.lamp
435         if not panel_node_draw(layout, lamp, 'OUTPUT_LAMP', 'Surface'):
436             layout.prop(lamp, "color")
437
438
439 class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel):
440     bl_label = "Surface"
441     bl_context = "world"
442
443     @classmethod
444     def poll(cls, context):
445         return context.world and CyclesButtonsPanel.poll(context)
446
447     def draw(self, context):
448         layout = self.layout
449
450         world = context.world
451         if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
452             layout.prop(world, "horizon_color", text="Color")
453
454
455 class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel):
456     bl_label = "Volume"
457     bl_context = "world"
458     bl_options = {'DEFAULT_CLOSED'}
459
460     @classmethod
461     def poll(cls, context):
462         # world = context.world
463         return False  # world and world.node_tree and CyclesButtonsPanel.poll(context)
464
465     def draw(self, context):
466         layout = self.layout
467         layout.active = False
468
469         world = context.world
470         panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
471
472
473 class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel):
474     bl_label = "Surface"
475     bl_context = "material"
476
477     @classmethod
478     def poll(cls, context):
479         return context.material and CyclesButtonsPanel.poll(context)
480
481     def draw(self, context):
482         layout = self.layout
483
484         mat = context.material
485         if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'):
486             layout.prop(mat, "diffuse_color")
487
488
489 class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel):
490     bl_label = "Volume"
491     bl_context = "material"
492     bl_options = {'DEFAULT_CLOSED'}
493
494     @classmethod
495     def poll(cls, context):
496         # mat = context.material
497         return False  # mat and mat.node_tree and CyclesButtonsPanel.poll(context)
498
499     def draw(self, context):
500         layout = self.layout
501         layout.active = False
502
503         mat = context.material
504         cmat = mat.cycles
505
506         panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
507
508         layout.prop(cmat, "homogeneous_volume")
509
510
511 class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
512     bl_label = "Displacement"
513     bl_context = "material"
514
515     @classmethod
516     def poll(cls, context):
517         mat = context.material
518         return mat and mat.node_tree and CyclesButtonsPanel.poll(context)
519
520     def draw(self, context):
521         layout = self.layout
522
523         mat = context.material
524         panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
525
526
527 class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
528     bl_label = "Settings"
529     bl_context = "material"
530     bl_options = {'DEFAULT_CLOSED'}
531
532     @classmethod
533     def poll(cls, context):
534         return context.material and CyclesButtonsPanel.poll(context)
535
536     def draw(self, context):
537         layout = self.layout
538
539         mat = context.material
540         cmat = mat.cycles
541
542         split = layout.split()
543
544         col = split.column()
545         col.prop(mat, "diffuse_color", text="Viewport Color")
546
547         col = split.column()
548         col.prop(cmat, "sample_as_light")
549
550
551 class CyclesTexture_PT_context(CyclesButtonsPanel, Panel):
552     bl_label = ""
553     bl_context = "texture"
554     bl_options = {'HIDE_HEADER'}
555     COMPAT_ENGINES = {'CYCLES'}
556
557     def draw(self, context):
558         layout = self.layout
559
560         tex = context.texture
561         space = context.space_data
562         pin_id = space.pin_id
563         use_pin_id = space.use_pin_id
564         user = context.texture_user
565         # node = context.texture_node
566
567         if not use_pin_id or not isinstance(pin_id, bpy.types.Texture):
568             pin_id = None
569
570         if not pin_id:
571             layout.template_texture_user()
572
573         if user:
574             layout.separator()
575
576             split = layout.split(percentage=0.65)
577             col = split.column()
578
579             if pin_id:
580                 col.template_ID(space, "pin_id")
581             elif user:
582                 col.template_ID(user, "texture", new="texture.new")
583
584             if tex:
585                 row = split.row()
586                 row.prop(tex, "use_nodes", icon="NODETREE", text="")
587                 row.label()
588
589                 if not tex.use_nodes:
590                     split = layout.split(percentage=0.2)
591                     split.label(text="Type:")
592                     split.prop(tex, "type", text="")
593
594
595 class CyclesTexture_PT_nodes(CyclesButtonsPanel, Panel):
596     bl_label = "Nodes"
597     bl_context = "texture"
598
599     @classmethod
600     def poll(cls, context):
601         tex = context.texture
602         return (tex and tex.use_nodes) and CyclesButtonsPanel.poll(context)
603
604     def draw(self, context):
605         layout = self.layout
606
607         tex = context.texture
608         panel_node_draw(layout, tex, 'OUTPUT_TEXTURE', 'Color')
609
610
611 class CyclesTexture_PT_node(CyclesButtonsPanel, Panel):
612     bl_label = "Node"
613     bl_context = "texture"
614
615     @classmethod
616     def poll(cls, context):
617         node = context.texture_node
618         return node and CyclesButtonsPanel.poll(context)
619
620     def draw(self, context):
621         layout = self.layout
622
623         node = context.texture_node
624         ntree = node.id_data
625         layout.template_node_view(ntree, node, None)
626
627
628 class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel):
629     bl_label = "Mapping"
630     bl_context = "texture"
631
632     @classmethod
633     def poll(cls, context):
634         tex = context.texture
635         node = context.texture_node
636         return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
637
638     def draw(self, context):
639         layout = self.layout
640
641         # tex = context.texture
642         node = context.texture_node
643
644         mapping = node.texture_mapping
645
646         row = layout.row()
647
648         row.column().prop(mapping, "location")
649         row.column().prop(mapping, "rotation")
650         row.column().prop(mapping, "scale")
651
652         layout.label(text="Projection:")
653
654         row = layout.row()
655         row.prop(mapping, "mapping_x", text="")
656         row.prop(mapping, "mapping_y", text="")
657         row.prop(mapping, "mapping_z", text="")
658
659
660 class CyclesTexture_PT_colors(CyclesButtonsPanel, Panel):
661     bl_label = "Color"
662     bl_context = "texture"
663     bl_options = {'DEFAULT_CLOSED'}
664
665     @classmethod
666     def poll(cls, context):
667         # tex = context.texture
668         # node = context.texture_node
669         return False
670         #return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
671
672     def draw(self, context):
673         layout = self.layout
674
675         # tex = context.texture
676         node = context.texture_node
677
678         mapping = node.color_mapping
679
680         split = layout.split()
681
682         col = split.column()
683         col.label(text="Blend:")
684         col.prop(mapping, "blend_type", text="")
685         col.prop(mapping, "blend_factor", text="Factor")
686         col.prop(mapping, "blend_color", text="")
687
688         col = split.column()
689         col.label(text="Adjust:")
690         col.prop(mapping, "brightness")
691         col.prop(mapping, "contrast")
692         col.prop(mapping, "saturation")
693
694         layout.separator()
695
696         layout.prop(mapping, "use_color_ramp", text="Ramp")
697         if mapping.use_color_ramp:
698             layout.template_color_ramp(mapping, "color_ramp", expand=True)
699
700
701 def draw_device(self, context):
702     scene = context.scene
703     layout = self.layout
704
705     if scene.render.engine == "CYCLES":
706         cscene = scene.cycles
707
708         available_devices = engine.available_devices()
709         available_cuda = 'cuda' in available_devices
710         available_opencl = 'opencl' in available_devices
711
712         if available_cuda or available_opencl:
713             layout.prop(cscene, "device")
714             if cscene.device == 'GPU' and available_cuda and available_opencl:
715                 layout.prop(cscene, "gpu_type")
716         if cscene.device == 'CPU' and engine.with_osl():
717             layout.prop(cscene, "shading_system")
718
719
720 def draw_pause(self, context):
721     layout = self.layout
722     scene = context.scene
723
724     if scene.render.engine == "CYCLES":
725         view = context.space_data
726
727         if view.viewport_shade == "RENDERED":
728             cscene = scene.cycles
729             layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
730
731
732 def get_panels():
733     return [
734         bpy.types.RENDER_PT_render,
735         bpy.types.RENDER_PT_output,
736         bpy.types.RENDER_PT_encoding,
737         bpy.types.RENDER_PT_dimensions,
738         bpy.types.RENDER_PT_stamp,
739         bpy.types.WORLD_PT_context_world,
740         bpy.types.DATA_PT_context_mesh,
741         bpy.types.DATA_PT_context_camera,
742         bpy.types.DATA_PT_context_lamp,
743         bpy.types.DATA_PT_texture_space,
744         bpy.types.DATA_PT_curve_texture_space,
745         bpy.types.DATA_PT_mball_texture_space,
746         bpy.types.DATA_PT_vertex_groups,
747         bpy.types.DATA_PT_shape_keys,
748         bpy.types.DATA_PT_uv_texture,
749         bpy.types.DATA_PT_vertex_colors,
750         bpy.types.DATA_PT_camera,
751         bpy.types.DATA_PT_camera_display,
752         bpy.types.DATA_PT_lens,
753         bpy.types.DATA_PT_custom_props_mesh,
754         bpy.types.DATA_PT_custom_props_camera,
755         bpy.types.DATA_PT_custom_props_lamp,
756         bpy.types.TEXTURE_PT_clouds,
757         bpy.types.TEXTURE_PT_wood,
758         bpy.types.TEXTURE_PT_marble,
759         bpy.types.TEXTURE_PT_magic,
760         bpy.types.TEXTURE_PT_blend,
761         bpy.types.TEXTURE_PT_stucci,
762         bpy.types.TEXTURE_PT_image,
763         bpy.types.TEXTURE_PT_image_sampling,
764         bpy.types.TEXTURE_PT_image_mapping,
765         bpy.types.TEXTURE_PT_musgrave,
766         bpy.types.TEXTURE_PT_voronoi,
767         bpy.types.TEXTURE_PT_distortednoise,
768         bpy.types.TEXTURE_PT_voxeldata,
769         bpy.types.TEXTURE_PT_pointdensity,
770         bpy.types.TEXTURE_PT_pointdensity_turbulence,
771         bpy.types.PARTICLE_PT_context_particles,
772         bpy.types.PARTICLE_PT_emission,
773         bpy.types.PARTICLE_PT_hair_dynamics,
774         bpy.types.PARTICLE_PT_cache,
775         bpy.types.PARTICLE_PT_velocity,
776         bpy.types.PARTICLE_PT_rotation,
777         bpy.types.PARTICLE_PT_physics,
778         bpy.types.PARTICLE_PT_boidbrain,
779         bpy.types.PARTICLE_PT_render,
780         bpy.types.PARTICLE_PT_draw,
781         bpy.types.PARTICLE_PT_children,
782         bpy.types.PARTICLE_PT_field_weights,
783         bpy.types.PARTICLE_PT_force_fields,
784         bpy.types.PARTICLE_PT_vertexgroups,
785         bpy.types.PARTICLE_PT_custom_props]
786
787
788 def register():
789     bpy.types.RENDER_PT_render.append(draw_device)
790     bpy.types.VIEW3D_HT_header.append(draw_pause)
791
792     for panel in get_panels():
793         panel.COMPAT_ENGINES.add('CYCLES')
794
795
796 def unregister():
797     bpy.types.RENDER_PT_render.remove(draw_device)
798     bpy.types.VIEW3D_HT_header.remove(draw_pause)
799
800     for panel in get_panels():
801         panel.COMPAT_ENGINES.remove('CYCLES')