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