misc small changes and bmesh support for testing script
[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         sub.prop(cscene, "use_cache")
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         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         rl = rd.layers[0]
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         if CyclesButtonsPanel.poll(context):
299             if context.mesh or context.curve or context.meta_ball:
300                 if context.scene.cycles.feature_set == 'EXPERIMENTAL':
301                     return True
302
303         return False
304
305     def draw(self, context):
306         layout = self.layout
307
308         mesh = context.mesh
309         curve = context.curve
310         mball = context.meta_ball
311
312         if mesh:
313             cdata = mesh.cycles
314         elif curve:
315             cdata = curve.cycles
316         elif mball:
317             cdata = mball.cycles
318
319         layout.prop(cdata, "displacement_method", text="Method")
320         layout.prop(cdata, "use_subdivision")
321         layout.prop(cdata, "dicing_rate")
322
323
324 class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
325     bl_label = "Ray Visibility"
326     bl_context = "object"
327     bl_options = {'DEFAULT_CLOSED'}
328
329     @classmethod
330     def poll(cls, context):
331         ob = context.object
332         return CyclesButtonsPanel.poll(context) and ob and ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META'}  # todo: 'LAMP'
333
334     def draw(self, context):
335         layout = self.layout
336
337         ob = context.object
338         visibility = ob.cycles_visibility
339
340         split = layout.split()
341
342         col = split.column()
343         col.prop(visibility, "camera")
344         col.prop(visibility, "diffuse")
345         col.prop(visibility, "glossy")
346
347         col = split.column()
348         col.prop(visibility, "transmission")
349         col.prop(visibility, "shadow")
350
351
352 def find_node(material, nodetype):
353     if material and material.node_tree:
354         ntree = material.node_tree
355
356         for node in ntree.nodes:
357             if getattr(node, "type", None) == nodetype:
358                 return node
359
360     return None
361
362
363 def find_node_input(node, name):
364     for input in node.inputs:
365         if input.name == name:
366             return input
367
368     return None
369
370
371 def panel_node_draw(layout, id_data, output_type, input_name):
372     if not id_data.node_tree:
373         layout.prop(id_data, "use_nodes", icon='NODETREE')
374         return False
375
376     ntree = id_data.node_tree
377
378     node = find_node(id_data, output_type)
379     if not node:
380         layout.label(text="No output node.")
381     else:
382         input = find_node_input(node, input_name)
383         layout.template_node_view(ntree, node, input)
384
385     return True
386
387
388 class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
389     bl_label = "Lamp"
390     bl_context = "data"
391
392     @classmethod
393     def poll(cls, context):
394         return context.lamp and CyclesButtonsPanel.poll(context)
395
396     def draw(self, context):
397         layout = self.layout
398
399         lamp = context.lamp
400         clamp = lamp.cycles
401
402         layout.prop(lamp, "type", expand=True)
403
404         split = layout.split()
405         col = split.column(align=True)
406
407         if lamp.type in {'POINT', 'SUN', 'SPOT'}:
408             col.prop(lamp, "shadow_soft_size", text="Size")
409         elif lamp.type == 'AREA':
410             col.prop(lamp, "shape", text="")
411             sub = col.column(align=True)
412
413             if lamp.shape == 'SQUARE':
414                 sub.prop(lamp, "size")
415             elif lamp.shape == 'RECTANGLE':
416                 sub.prop(lamp, "size", text="Size X")
417                 sub.prop(lamp, "size_y", text="Size Y")
418
419         col = split.column()
420         col.prop(clamp, "cast_shadow")
421
422         if lamp.type == 'SPOT':
423             layout.label(text="Not supported, interpreted as point lamp.")
424         elif lamp.type == 'HEMI':
425             layout.label(text="Not supported, interpreted as sun lamp.")
426
427
428 class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
429     bl_label = "Nodes"
430     bl_context = "data"
431
432     @classmethod
433     def poll(cls, context):
434         return context.lamp and CyclesButtonsPanel.poll(context)
435
436     def draw(self, context):
437         layout = self.layout
438
439         lamp = context.lamp
440         if not panel_node_draw(layout, lamp, 'OUTPUT_LAMP', 'Surface'):
441             layout.prop(lamp, "color")
442
443
444 class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel):
445     bl_label = "Surface"
446     bl_context = "world"
447
448     @classmethod
449     def poll(cls, context):
450         return context.world and CyclesButtonsPanel.poll(context)
451
452     def draw(self, context):
453         layout = self.layout
454
455         world = context.world
456         if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
457             layout.prop(world, "horizon_color", text="Color")
458
459
460 class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel):
461     bl_label = "Volume"
462     bl_context = "world"
463     bl_options = {'DEFAULT_CLOSED'}
464
465     @classmethod
466     def poll(cls, context):
467         # world = context.world
468         # world and world.node_tree and CyclesButtonsPanel.poll(context)
469         return False
470
471     def draw(self, context):
472         layout = self.layout
473         layout.active = False
474
475         world = context.world
476         panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
477
478
479 class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel):
480     bl_label = "Surface"
481     bl_context = "material"
482
483     @classmethod
484     def poll(cls, context):
485         return context.material and CyclesButtonsPanel.poll(context)
486
487     def draw(self, context):
488         layout = self.layout
489
490         mat = context.material
491         if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'):
492             layout.prop(mat, "diffuse_color")
493
494
495 class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel):
496     bl_label = "Volume"
497     bl_context = "material"
498     bl_options = {'DEFAULT_CLOSED'}
499
500     @classmethod
501     def poll(cls, context):
502         # mat = context.material
503         # mat and mat.node_tree and CyclesButtonsPanel.poll(context)
504         return False
505
506     def draw(self, context):
507         layout = self.layout
508         layout.active = False
509
510         mat = context.material
511         cmat = mat.cycles
512
513         panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
514
515         layout.prop(cmat, "homogeneous_volume")
516
517
518 class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
519     bl_label = "Displacement"
520     bl_context = "material"
521
522     @classmethod
523     def poll(cls, context):
524         mat = context.material
525         return mat and mat.node_tree and CyclesButtonsPanel.poll(context)
526
527     def draw(self, context):
528         layout = self.layout
529
530         mat = context.material
531         panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
532
533
534 class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
535     bl_label = "Settings"
536     bl_context = "material"
537     bl_options = {'DEFAULT_CLOSED'}
538
539     @classmethod
540     def poll(cls, context):
541         return context.material and CyclesButtonsPanel.poll(context)
542
543     def draw(self, context):
544         layout = self.layout
545
546         mat = context.material
547         cmat = mat.cycles
548
549         split = layout.split()
550
551         col = split.column()
552         col.prop(mat, "diffuse_color", text="Viewport Color")
553
554         col = split.column()
555         col.prop(cmat, "sample_as_light")
556
557
558 class CyclesTexture_PT_context(CyclesButtonsPanel, Panel):
559     bl_label = ""
560     bl_context = "texture"
561     bl_options = {'HIDE_HEADER'}
562     COMPAT_ENGINES = {'CYCLES'}
563
564     def draw(self, context):
565         layout = self.layout
566
567         tex = context.texture
568         space = context.space_data
569         pin_id = space.pin_id
570         use_pin_id = space.use_pin_id
571         user = context.texture_user
572         # node = context.texture_node
573
574         if not use_pin_id or not isinstance(pin_id, bpy.types.Texture):
575             pin_id = None
576
577         if not pin_id:
578             layout.template_texture_user()
579
580         if user:
581             layout.separator()
582
583             split = layout.split(percentage=0.65)
584             col = split.column()
585
586             if pin_id:
587                 col.template_ID(space, "pin_id")
588             elif user:
589                 col.template_ID(user, "texture", new="texture.new")
590
591             if tex:
592                 row = split.row()
593                 row.prop(tex, "use_nodes", icon="NODETREE", text="")
594                 row.label()
595
596                 if not tex.use_nodes:
597                     split = layout.split(percentage=0.2)
598                     split.label(text="Type:")
599                     split.prop(tex, "type", text="")
600
601
602 class CyclesTexture_PT_nodes(CyclesButtonsPanel, Panel):
603     bl_label = "Nodes"
604     bl_context = "texture"
605
606     @classmethod
607     def poll(cls, context):
608         tex = context.texture
609         return (tex and tex.use_nodes) and CyclesButtonsPanel.poll(context)
610
611     def draw(self, context):
612         layout = self.layout
613
614         tex = context.texture
615         panel_node_draw(layout, tex, 'OUTPUT_TEXTURE', 'Color')
616
617
618 class CyclesTexture_PT_node(CyclesButtonsPanel, Panel):
619     bl_label = "Node"
620     bl_context = "texture"
621
622     @classmethod
623     def poll(cls, context):
624         node = context.texture_node
625         return node and CyclesButtonsPanel.poll(context)
626
627     def draw(self, context):
628         layout = self.layout
629
630         node = context.texture_node
631         ntree = node.id_data
632         layout.template_node_view(ntree, node, None)
633
634
635 class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel):
636     bl_label = "Mapping"
637     bl_context = "texture"
638
639     @classmethod
640     def poll(cls, context):
641         tex = context.texture
642         node = context.texture_node
643         return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
644
645     def draw(self, context):
646         layout = self.layout
647
648         # tex = context.texture
649         node = context.texture_node
650
651         mapping = node.texture_mapping
652
653         row = layout.row()
654
655         row.column().prop(mapping, "location")
656         row.column().prop(mapping, "rotation")
657         row.column().prop(mapping, "scale")
658
659         layout.label(text="Projection:")
660
661         row = layout.row()
662         row.prop(mapping, "mapping_x", text="")
663         row.prop(mapping, "mapping_y", text="")
664         row.prop(mapping, "mapping_z", text="")
665
666
667 class CyclesTexture_PT_colors(CyclesButtonsPanel, Panel):
668     bl_label = "Color"
669     bl_context = "texture"
670     bl_options = {'DEFAULT_CLOSED'}
671
672     @classmethod
673     def poll(cls, context):
674         # tex = context.texture
675         # node = context.texture_node
676         return False
677         #return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
678
679     def draw(self, context):
680         layout = self.layout
681
682         # tex = context.texture
683         node = context.texture_node
684
685         mapping = node.color_mapping
686
687         split = layout.split()
688
689         col = split.column()
690         col.label(text="Blend:")
691         col.prop(mapping, "blend_type", text="")
692         col.prop(mapping, "blend_factor", text="Factor")
693         col.prop(mapping, "blend_color", text="")
694
695         col = split.column()
696         col.label(text="Adjust:")
697         col.prop(mapping, "brightness")
698         col.prop(mapping, "contrast")
699         col.prop(mapping, "saturation")
700
701         layout.separator()
702
703         layout.prop(mapping, "use_color_ramp", text="Ramp")
704         if mapping.use_color_ramp:
705             layout.template_color_ramp(mapping, "color_ramp", expand=True)
706
707
708 def draw_device(self, context):
709     scene = context.scene
710     layout = self.layout
711
712     if scene.render.engine == 'CYCLES':
713         cscene = scene.cycles
714
715         layout.prop(cscene, "feature_set")
716
717         device_type = context.user_preferences.system.compute_device_type
718         if device_type == 'CUDA':
719             layout.prop(cscene, "device")
720         elif device_type == 'OPENCL' and cscene.feature_set == 'EXPERIMENTAL':
721             layout.prop(cscene, "device")
722
723
724 def draw_pause(self, context):
725     layout = self.layout
726     scene = context.scene
727
728     if scene.render.engine == "CYCLES":
729         view = context.space_data
730
731         if view.viewport_shade == 'RENDERED':
732             cscene = scene.cycles
733             layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
734
735
736 def get_panels():
737     return (
738         bpy.types.RENDER_PT_render,
739         bpy.types.RENDER_PT_output,
740         bpy.types.RENDER_PT_encoding,
741         bpy.types.RENDER_PT_dimensions,
742         bpy.types.RENDER_PT_stamp,
743         bpy.types.SCENE_PT_scene,
744         bpy.types.SCENE_PT_audio,
745         bpy.types.SCENE_PT_unit,
746         bpy.types.SCENE_PT_keying_sets,
747         bpy.types.SCENE_PT_keying_set_paths,
748         bpy.types.SCENE_PT_physics,
749         bpy.types.WORLD_PT_context_world,
750         bpy.types.DATA_PT_context_mesh,
751         bpy.types.DATA_PT_context_camera,
752         bpy.types.DATA_PT_context_lamp,
753         bpy.types.DATA_PT_texture_space,
754         bpy.types.DATA_PT_curve_texture_space,
755         bpy.types.DATA_PT_mball_texture_space,
756         bpy.types.DATA_PT_vertex_groups,
757         bpy.types.DATA_PT_shape_keys,
758         bpy.types.DATA_PT_uv_texture,
759         bpy.types.DATA_PT_vertex_colors,
760         bpy.types.DATA_PT_camera,
761         bpy.types.DATA_PT_camera_display,
762         bpy.types.DATA_PT_lens,
763         bpy.types.DATA_PT_custom_props_mesh,
764         bpy.types.DATA_PT_custom_props_camera,
765         bpy.types.DATA_PT_custom_props_lamp,
766         bpy.types.TEXTURE_PT_clouds,
767         bpy.types.TEXTURE_PT_wood,
768         bpy.types.TEXTURE_PT_marble,
769         bpy.types.TEXTURE_PT_magic,
770         bpy.types.TEXTURE_PT_blend,
771         bpy.types.TEXTURE_PT_stucci,
772         bpy.types.TEXTURE_PT_image,
773         bpy.types.TEXTURE_PT_image_sampling,
774         bpy.types.TEXTURE_PT_image_mapping,
775         bpy.types.TEXTURE_PT_musgrave,
776         bpy.types.TEXTURE_PT_voronoi,
777         bpy.types.TEXTURE_PT_distortednoise,
778         bpy.types.TEXTURE_PT_voxeldata,
779         bpy.types.TEXTURE_PT_pointdensity,
780         bpy.types.TEXTURE_PT_pointdensity_turbulence,
781         bpy.types.PARTICLE_PT_context_particles,
782         bpy.types.PARTICLE_PT_emission,
783         bpy.types.PARTICLE_PT_hair_dynamics,
784         bpy.types.PARTICLE_PT_cache,
785         bpy.types.PARTICLE_PT_velocity,
786         bpy.types.PARTICLE_PT_rotation,
787         bpy.types.PARTICLE_PT_physics,
788         bpy.types.PARTICLE_PT_boidbrain,
789         bpy.types.PARTICLE_PT_render,
790         bpy.types.PARTICLE_PT_draw,
791         bpy.types.PARTICLE_PT_children,
792         bpy.types.PARTICLE_PT_field_weights,
793         bpy.types.PARTICLE_PT_force_fields,
794         bpy.types.PARTICLE_PT_vertexgroups,
795         bpy.types.PARTICLE_PT_custom_props,
796         )
797
798
799 def register():
800     bpy.types.RENDER_PT_render.append(draw_device)
801     bpy.types.VIEW3D_HT_header.append(draw_pause)
802
803     for panel in get_panels():
804         panel.COMPAT_ENGINES.add('CYCLES')
805
806
807 def unregister():
808     bpy.types.RENDER_PT_render.remove(draw_device)
809     bpy.types.VIEW3D_HT_header.remove(draw_pause)
810
811     for panel in get_panels():
812         panel.COMPAT_ENGINES.remove('CYCLES')