Keyed physics refresh:
[blender-staging.git] / release / ui / buttons_particle.py
1
2 import bpy
3
4 def particle_panel_enabled(psys):
5         return psys.point_cache.baked==False and psys.editable==False
6         
7 def particle_panel_poll(context):
8         psys = context.particle_system
9         if psys==None:  return False
10         if psys.settings==None:  return False
11         return psys.settings.type in ('EMITTER', 'REACTOR', 'HAIR')
12
13 class ParticleButtonsPanel(bpy.types.Panel):
14         __space_type__ = "BUTTONS_WINDOW"
15         __region_type__ = "WINDOW"
16         __context__ = "particle"
17
18         def poll(self, context):
19                 return particle_panel_poll(context)
20
21 class PARTICLE_PT_particles(ParticleButtonsPanel):
22         __idname__= "PARTICLE_PT_particles"
23         __no_header__ = True
24
25         def poll(self, context):
26                 return (context.particle_system or context.object)
27
28         def draw(self, context):
29                 layout = self.layout
30                 ob = context.object
31                 psys = context.particle_system
32
33                 if ob:
34                         row = layout.row()
35
36                         row.template_list(ob, "particle_systems", ob, "active_particle_system_index")
37
38                         col = row.column(align=True)
39                         col.itemO("OBJECT_OT_particle_system_add", icon="ICON_ZOOMIN", text="")
40                         col.itemO("OBJECT_OT_particle_system_remove", icon="ICON_ZOOMOUT", text="")
41
42                 if psys:
43                         split = layout.split(percentage=0.65)
44                         
45                         split.template_ID(psys, "settings", new="PARTICLE_OT_new")
46                         
47                         #row = layout.row()
48                         #row.itemL(text="Viewport")
49                         #row.itemL(text="Render")
50                         
51                         part = psys.settings
52                         
53                         if part:
54                                 ptype = psys.settings.type
55                                 if ptype not in ('EMITTER', 'REACTOR', 'HAIR'):
56                                         layout.itemL(text="No settings for fluid particles")
57                                         return
58                                         
59                                 split = layout.split(percentage=0.65)
60                                 
61                                 split.enabled = particle_panel_enabled(psys)
62                                 split.itemR(part, "type")
63                                 split.itemR(psys, "seed")
64                                 
65                                 split = layout.split(percentage=0.65)
66                                 if part.type=='HAIR':
67                                         if psys.editable==True:
68                                                 split.itemO("PARTICLE_OT_editable_set", text="Free Edit")
69                                         else:
70                                                 split.itemO("PARTICLE_OT_editable_set", text="Make Editable")
71                                         row = split.row()
72                                         row.enabled = particle_panel_enabled(psys)
73                                         row.itemR(part, "hair_step")
74                                 elif part.type=='REACTOR':
75                                         split.enabled = particle_panel_enabled(psys)
76                                         split.itemR(psys, "reactor_target_object")
77                                         split.itemR(psys, "reactor_target_particle_system", text="Particle System")
78                 
79 class PARTICLE_PT_emission(ParticleButtonsPanel):
80         __idname__= "PARTICLE_PT_emission"
81         __label__ = "Emission"
82         
83         def draw(self, context):
84                 layout = self.layout
85
86                 psys = context.particle_system
87                 part = psys.settings
88                 
89                 layout.enabled = particle_panel_enabled(psys)
90                 
91                 row = layout.row()
92                 row.itemR(part, "amount")
93                 
94                 split = layout.split()
95                 
96                 col = split.column(align=True)
97                 col.itemR(part, "start")
98                 col.itemR(part, "end")
99
100                 col = split.column(align=True)
101                 col.itemR(part, "lifetime")
102                 col.itemR(part, "random_lifetime", slider=True)
103                 
104                 layout.row().itemL(text="Emit From:")
105                 
106                 row = layout.row()
107                 row.itemR(part, "emit_from", expand=True)
108                 row = layout.row()
109                 row.itemR(part, "trand")
110                 if part.distribution!='GRID':
111                         row.itemR(part, "even_distribution")
112                 
113                 if part.emit_from=='FACE' or part.emit_from=='VOLUME':
114                         row = layout.row()
115                         row.itemR(part, "distribution", expand=True)
116                         
117                         row = layout.row()
118
119                         if part.distribution=='JIT':
120                                 row.itemR(part, "userjit", text="Particles/Face")
121                                 row.itemR(part, "jitter_factor", text="Jittering Amount", slider=True)
122                         elif part.distribution=='GRID':
123                                 row.itemR(part, "grid_resolution")
124
125 class PARTICLE_PT_cache(ParticleButtonsPanel):
126         __idname__= "PARTICLE_PT_cache"
127         __label__ = "Cache"
128         __default_closed__ = True
129         
130         def poll(self, context):
131                 psys = context.particle_system
132                 if psys==None:  return False
133                 if psys.settings==None:  return False
134                 phystype = psys.settings.physics_type
135                 if phystype == 'NO' or phystype == 'KEYED':
136                         return False
137                 return psys.settings.type in ('EMITTER', 'REACTOR')
138
139         def draw(self, context):
140                 layout = self.layout
141
142                 psys = context.particle_system
143                 part = psys.settings
144                 cache = psys.point_cache
145                 
146                 row = layout.row()
147                 row.itemR(cache, "name")
148                 
149                 row = layout.row()
150                 
151                 if cache.baked == True:
152                         row.itemO("PTCACHE_OT_free_bake_particle_system", text="Free Bake")
153                 else:
154                         row.item_booleanO("PTCACHE_OT_cache_particle_system", "bake", True, text="Bake")
155                 
156                 subrow = row.row()
157                 subrow.enabled = (cache.frames_skipped or cache.outdated) and particle_panel_enabled(psys)
158                 subrow.itemO("PTCACHE_OT_cache_particle_system", text="Calculate to Current Frame")
159                 
160                 row = layout.row()
161                 row.enabled = particle_panel_enabled(psys)
162                 row.itemO("PTCACHE_OT_bake_from_particles_cache", text="Current Cache to Bake")
163                 row.itemR(cache, "step");
164         
165                 row = layout.row()
166                 row.enabled = particle_panel_enabled(psys)
167                 row.itemR(cache, "quick_cache")
168                 row.itemR(cache, "disk_cache")
169                 
170                 layout.itemL(text=cache.info)
171                 
172                 layout.itemS()
173                 
174                 row = layout.row()
175                 row.item_booleanO("PTCACHE_OT_bake_all", "bake", True, text="Bake All Dynamics")
176                 row.itemO("PTCACHE_OT_free_bake_all", text="Free All Bakes")
177                 layout.itemO("PTCACHE_OT_bake_all", text="Update All Dynamics to current frame")
178                 
179                 # for particles these are figured out automatically
180                 #row.itemR(cache, "start_frame")
181                 #row.itemR(cache, "end_frame")
182
183 class PARTICLE_PT_initial(ParticleButtonsPanel):
184         __idname__= "PARTICLE_PT_initial"
185         __label__ = "Velocity"
186
187         def draw(self, context):
188                 layout = self.layout
189
190                 psys = context.particle_system
191                 part = psys.settings
192                 
193                 layout.enabled = particle_panel_enabled(psys)
194                                 
195                 layout.row().itemL(text="Direction:")
196         
197                 split = layout.split()
198                         
199                 sub = split.column()
200                 sub.itemR(part, "normal_factor")
201                 if part.emit_from=='PARTICLE':
202                         sub.itemR(part, "particle_factor")
203                 else:
204                         sub.itemR(part, "object_factor", slider=True)
205                 sub.itemR(part, "random_factor")
206                 sub.itemR(part, "tangent_factor")
207                 sub.itemR(part, "tangent_phase", slider=True)
208                 
209                 sub = split.column()
210                 sub.itemL(text="TODO:")
211                 sub.itemL(text="Object aligned")
212                 sub.itemL(text="direction: X, Y, Z")
213                 
214                 if part.type=='REACTOR':
215                         sub.itemR(part, "reactor_factor")
216                         sub.itemR(part, "reaction_shape", slider=True)
217                 else:
218                         sub.itemL(text="")
219                 
220                 layout.row().itemL(text="Rotation:")
221                 split = layout.split()
222                         
223                 sub = split.column()
224                 
225                 sub.itemR(part, "rotation_mode", text="Axis")
226                 split = layout.split()
227                         
228                 sub = split.column()
229                 sub.itemR(part, "rotation_dynamic")
230                 sub.itemR(part, "random_rotation_factor", slider=True)
231                 sub = split.column()
232                 sub.itemR(part, "phase_factor", slider=True)
233                 sub.itemR(part, "random_phase_factor", text="Random", slider=True)
234
235                 layout.row().itemL(text="Angular velocity:")
236                 layout.row().itemR(part, "angular_velocity_mode", expand=True)
237                 split = layout.split()
238                         
239                 sub = split.column()
240                 
241                 sub.itemR(part, "angular_velocity_factor", text="")
242                 
243 class PARTICLE_PT_physics(ParticleButtonsPanel):
244         __idname__= "PARTICLE_PT_physics"
245         __label__ = "Physics"
246
247         def draw(self, context):
248                 layout = self.layout
249
250                 psys = context.particle_system
251                 part = psys.settings
252                 
253                 layout.enabled = layout.enabled = particle_panel_enabled(psys)
254
255                 row = layout.row()
256                 row.itemR(part, "physics_type", expand=True)
257                 if part.physics_type != 'NO':
258                         layout.itemR(part, "effector_group")
259                 
260                         row = layout.row()
261                         col = row.column(align=True)
262                         col.itemR(part, "particle_size")
263                         col.itemR(part, "random_size", slider=True)
264                         col = row.column(align=True)
265                         col.itemR(part, "mass")
266                         col.itemR(part, "sizemass", text="Multiply mass with size")
267                                                         
268                         split = layout.split()
269                         
270                         sub = split.column()
271                         
272                 if part.physics_type == 'NEWTON':
273                         
274                         sub.itemL(text="Forces:")
275                         sub.itemR(part, "brownian_factor")
276                         sub.itemR(part, "drag_factor", slider=True)
277                         sub.itemR(part, "damp_factor", slider=True)
278                         sub.itemR(part, "integrator")
279                         sub = split.column()
280                         sub.itemR(part, "acceleration")
281                         
282                 elif part.physics_type == 'KEYED':
283                         row = layout.row()
284                         col = row.column()
285                         col.active = not psys.keyed_timing
286                         col.itemR(part, "keyed_loops", text="Loops")
287                         row.itemR(psys, "keyed_timing", text="Use Timing")
288                         
289                         layout.itemL(text="Keys:")
290                         row = layout.row()
291                         
292                         row.template_list(psys, "keyed_targets", psys, "active_keyed_target_index")
293                         
294                         col = row.column()
295                         subrow = col.row()
296                         subcol = subrow.column(align=True)
297                         subcol.itemO("PARTICLE_OT_new_keyed_target", icon="ICON_ZOOMIN", text="")
298                         subcol.itemO("PARTICLE_OT_remove_keyed_target", icon="ICON_ZOOMOUT", text="")
299                         subrow = col.row()
300                         subcol = subrow.column(align=True)
301                         subcol.itemO("PARTICLE_OT_keyed_target_move_up", icon="VICON_MOVE_UP", text="")
302                         subcol.itemO("PARTICLE_OT_keyed_target_move_down", icon="VICON_MOVE_DOWN", text="")
303                         
304                         key = psys.active_keyed_target
305                         if key:
306                                 row = layout.row()
307                                 col = row.column()
308                                 #doesn't work yet
309                                 #col.red_alert = key.valid
310                                 col.itemR(key, "object", text="")
311                                 col.itemR(key, "system", text="System")
312                                 col = row.column();
313                                 col.active = psys.keyed_timing
314                                 col.itemR(key, "time")
315                                 col.itemR(key, "duration")
316                         
317                 if part.physics_type=='NEWTON' or part.physics_type=='BOIDS':
318
319                         sub.itemR(part, "size_deflect")
320                         sub.itemR(part, "die_on_collision")
321                         sub.itemR(part, "sticky")
322
323 class PARTICLE_PT_render(ParticleButtonsPanel):
324         __idname__= "PARTICLE_PT_render"
325         __label__ = "Render"
326         
327         def poll(self, context):
328                 psys = context.particle_system
329                 if psys==None: return False
330                 if psys.settings==None: return False
331                 return True;
332                 
333         def draw(self, context):
334                 layout = self.layout
335
336                 psys = context.particle_system
337                 part = psys.settings
338
339                 row = layout.row()
340                 row.itemR(part, "material")
341                 row.itemR(psys, "parent");
342                 
343                 split = layout.split()
344                         
345                 sub = split.column()
346                 sub.itemR(part, "emitter");
347                 sub.itemR(part, "parent");
348                 sub = split.column()
349                 sub.itemR(part, "unborn");
350                 sub.itemR(part, "died");
351                 
352                 row = layout.row()
353                 row.itemR(part, "ren_as", expand=True)
354                 
355                 split = layout.split()
356                         
357                 sub = split.column()
358                 
359                 if part.ren_as == 'LINE':
360                         sub.itemR(part, "line_length_tail")
361                         sub.itemR(part, "line_length_head")
362                         sub = split.column()
363                         sub.itemR(part, "velocity_length")
364                 elif part.ren_as == 'PATH':
365                 
366                         if (part.type!='HAIR' and part.physics_type!='KEYED' and psys.point_cache.baked==False):
367                                 box = layout.box()
368                                 box.itemL(text="Baked or keyed particles needed for correct rendering.")
369                                 return
370                                 
371                         sub.itemR(part, "render_strand")
372                         colsub = sub.column()
373                         colsub.active = part.render_strand == False
374                         colsub.itemR(part, "render_adaptive")
375                         colsub = sub.column()
376                         colsub.active = part.render_adaptive or part.render_strand == True
377                         colsub.itemR(part, "adaptive_angle")
378                         colsub = sub.column()
379                         colsub.active = part.render_adaptive == True and part.render_strand == False
380                         colsub.itemR(part, "adaptive_pix")
381                         sub.itemR(part, "hair_bspline")
382                         sub.itemR(part, "render_step", text="Steps")
383                         sub = split.column()    
384
385                         sub.itemL(text="Timing:")
386                         sub.itemR(part, "abs_path_time")
387                         sub.itemR(part, "path_start", text="Start", slider= not part.abs_path_time)
388                         sub.itemR(part, "path_end", text="End", slider= not part.abs_path_time)         
389                         sub.itemR(part, "random_length", text="Random", slider=True)
390                         
391                         row = layout.row()
392                         col = row.column()
393                         
394                         if part.type=='HAIR' and part.render_strand==True and part.child_type=='FACES':
395                                 layout.itemR(part, "enable_simplify")
396                                 if part.enable_simplify==True:
397                                         row = layout.row()
398                                         row.itemR(part, "simplify_refsize")
399                                         row.itemR(part, "simplify_rate")
400                                         row.itemR(part, "simplify_transition")
401                                         row = layout.row()
402                                         row.itemR(part, "viewport")
403                                         subrow = row.row()
404                                         subrow.active = part.viewport==True
405                                         subrow.itemR(part, "simplify_viewport")
406                         
407
408                 elif part.ren_as == 'OBJECT':
409                         sub.itemR(part, "dupli_object")
410                 elif part.ren_as == 'GROUP':
411                         sub.itemR(part, "dupli_group")
412                         split = layout.split()
413                         sub = split.column()
414                         sub.itemR(part, "whole_group")
415                         sub = split.column()
416                         colsub = sub.column()
417                         colsub.active = part.whole_group == False
418                         colsub.itemR(part, "rand_group")
419                         
420                 elif part.ren_as == 'BILLBOARD':
421                         sub.itemL(text="Align:")
422                         
423                         row = layout.row()
424                         row.itemR(part, "billboard_align", expand=True)
425                         row.itemR(part, "billboard_lock", text="Lock")
426                         row = layout.row()
427                         row.itemR(part, "billboard_object")
428                 
429                         row = layout.row()
430                         col = row.column(align=True)
431                         col.itemL(text="Tilt:")
432                         col.itemR(part, "billboard_tilt", text="Angle", slider=True)
433                         col.itemR(part, "billboard_random_tilt", slider=True)
434                         col = row.column()
435                         col.itemR(part, "billboard_offset")
436                         
437                         row = layout.row()
438                         row.itemR(psys, "billboard_normal_uv")
439                         row = layout.row()
440                         row.itemR(psys, "billboard_time_index_uv")
441                         
442                         row = layout.row()
443                         row.itemL(text="Split uv's:")
444                         row.itemR(part, "billboard_uv_split", text="Number of splits")
445                         row = layout.row()
446                         row.itemR(psys, "billboard_split_uv")
447                         row = layout.row()
448                         row.itemL(text="Animate:")
449                         row.itemR(part, "billboard_animation", expand=True)
450                         row.itemL(text="Offset:")
451                         row.itemR(part, "billboard_split_offset", expand=True)
452                 if part.ren_as == 'HALO' or part.ren_as == 'LINE' or part.ren_as=='BILLBOARD':
453                         row = layout.row()
454                         col = row.column()
455                         col.itemR(part, "trail_count")
456                         if part.trail_count > 1:
457                                 col.itemR(part, "abs_path_time", text="Length in frames")
458                                 col = row.column()
459                                 col.itemR(part, "path_end", text="Length", slider=not part.abs_path_time)
460                                 col.itemR(part, "random_length", text="Random", slider=True)
461                         else:
462                                 col = row.column()
463                                 col.itemL(text="")
464                                 
465 class PARTICLE_PT_draw(ParticleButtonsPanel):
466         __idname__= "PARTICLE_PT_draw"
467         __label__ = "Display"
468         __default_closed__ = True
469         
470         def poll(self, context):
471                 psys = context.particle_system
472                 if psys==None: return False
473                 if psys.settings==None: return False
474                 return True;
475         
476         def draw(self, context):
477                 layout = self.layout
478
479                 psys = context.particle_system
480                 part = psys.settings
481                 
482                 row = layout.row()
483                 row.itemR(part, "draw_as", expand=True)
484                 
485                 if part.draw_as=='NONE' or (part.ren_as=='NONE' and part.draw_as=='RENDER'):
486                         return
487                         
488                 path = (part.ren_as=='PATH' and part.draw_as=='RENDER') or part.draw_as=='PATH'
489                         
490                 if path and part.type!='HAIR' and part.physics_type!='KEYED' and psys.point_cache.baked==False:
491                         box = layout.box()
492                         box.itemL(text="Baked or keyed particles needed for correct drawing.")
493                         return
494                 
495                 row = layout.row()
496                 row.itemR(part, "display", slider=True)
497                 if part.draw_as!='RENDER' or part.ren_as=='HALO':
498                         row.itemR(part, "draw_size")
499                 else:
500                         row.itemL(text="")
501                 
502                 row = layout.row()
503                 col = row.column()
504                 col.itemR(part, "show_size")
505                 col.itemR(part, "velocity")
506                 col.itemR(part, "num")
507                 if part.physics_type == 'BOIDS':
508                         col.itemR(part, "draw_health")
509                 
510                 col = row.column()
511                 col.itemR(part, "material_color", text="Use material color")
512                 
513                 if (path):
514                         box = col.box()                         
515                         box.itemR(part, "draw_step")
516                 else:
517                         subcol = col.column()
518                         subcol.active = part.material_color==False
519                         #subcol.itemL(text="color")
520                         #subcol.itemL(text="Override material color")
521
522 class PARTICLE_PT_children(ParticleButtonsPanel):
523         __idname__= "PARTICLE_PT_children"
524         __label__ = "Children"
525         __default_closed__ = True
526
527         def draw(self, context):
528                 layout = self.layout
529
530                 psys = context.particle_system
531                 part = psys.settings
532                 
533                 layout.row().itemR(part, "child_type", expand=True)
534                 
535                 if part.child_type=='NONE':
536                         return
537                 
538                 row = layout.row()
539                 
540                 col = row.column(align=True)
541                 col.itemR(part, "child_nbr", text="Display")
542                 col.itemR(part, "rendered_child_nbr", text="Render")
543                 
544                 col = row.column(align=True)
545                 
546                 if part.child_type=='FACES':
547                         col.itemR(part, "virtual_parents", slider=True)
548                 else:
549                         col.itemR(part, "child_radius", text="Radius")
550                         col.itemR(part, "child_roundness", text="Roundness", slider=True)
551                 
552                         col = row.column(align=True)
553                         col.itemR(part, "child_size", text="Size")
554                         col.itemR(part, "child_random_size", text="Random")
555                 
556                 layout.row().itemL(text="Effects:")
557                 
558                 row = layout.row()
559                 
560                 col = row.column(align=True)
561                 col.itemR(part, "clump_factor", slider=True)
562                 col.itemR(part, "clumppow", slider=True)
563                 
564                 col = row.column(align=True)
565                 col.itemR(part, "rough_endpoint")
566                 col.itemR(part, "rough_end_shape")
567
568                 row = layout.row()
569                 
570                 col = row.column(align=True)
571                 col.itemR(part, "rough1")
572                 col.itemR(part, "rough1_size")
573
574                 col = row.column(align=True)
575                 col.itemR(part, "rough2")
576                 col.itemR(part, "rough2_size")
577                 col.itemR(part, "rough2_thres", slider=True)
578                 
579                 row = layout.row()
580                 col = row.column(align=True)
581                 col.itemR(part, "child_length", slider=True)
582                 col.itemR(part, "child_length_thres", slider=True)
583                 
584                 col = row.column(align=True)
585                 col.itemL(text="Space reserved for")
586                 col.itemL(text="hair parting controls")
587                 
588                 layout.row().itemL(text="Kink:")
589                 layout.row().itemR(part, "kink", expand=True)
590                 
591                 split = layout.split()
592                 
593                 sub = split.column()
594                 sub.itemR(part, "kink_amplitude")
595                 sub.itemR(part, "kink_frequency")
596                 sub = split.column()
597                 sub.itemR(part, "kink_shape", slider=True)
598
599 class PARTICLE_PT_vertexgroups(ParticleButtonsPanel):
600         __idname__= "PARTICLE_PT_vertexgroups"
601         __label__ = "Vertexgroups"
602         __default_closed__ = True
603
604         def draw(self, context):
605                 layout = self.layout
606
607                 psys = context.particle_system
608                 part = psys.settings
609                 
610                 layout.itemL(text="Nothing here yet.")
611
612                 #row = layout.row()
613                 #row.itemL(text="Vertex Group")
614                 #row.itemL(text="Negate")
615
616                 
617                 #row = layout.row()
618                 #row.itemR(psys, "vertex_group_density")
619                 #row.itemR(psys, "vertex_group_density_negate", text="")
620                 
621                 #row = layout.row()
622                 #row.itemR(psys, "vertex_group_velocity")
623                 #row.itemR(psys, "vertex_group_velocity_negate", text="")
624                 
625                 #row = layout.row()
626                 #row.itemR(psys, "vertex_group_length")
627                 #row.itemR(psys, "vertex_group_length_negate", text="")
628                 
629                 #row = layout.row()
630                 #row.itemR(psys, "vertex_group_clump")
631                 #row.itemR(psys, "vertex_group_clump_negate", text="")
632                 
633                 #row = layout.row()
634                 #row.itemR(psys, "vertex_group_kink")
635                 #row.itemR(psys, "vertex_group_kink_negate", text="")
636                 
637                 #row = layout.row()
638                 #row.itemR(psys, "vertex_group_roughness1")
639                 #row.itemR(psys, "vertex_group_roughness1_negate", text="")
640                 
641                 #row = layout.row()
642                 #row.itemR(psys, "vertex_group_roughness2")
643                 #row.itemR(psys, "vertex_group_roughness2_negate", text="")
644                 
645                 #row = layout.row()
646                 #row.itemR(psys, "vertex_group_roughness_end")
647                 #row.itemR(psys, "vertex_group_roughness_end_negate", text="")
648
649                 #row = layout.row()
650                 #row.itemR(psys, "vertex_group_size")
651                 #row.itemR(psys, "vertex_group_size_negate", text="")
652                 
653                 #row = layout.row()
654                 #row.itemR(psys, "vertex_group_tangent")
655                 #row.itemR(psys, "vertex_group_tangent_negate", text="")
656                 
657                 #row = layout.row()
658                 #row.itemR(psys, "vertex_group_rotation")
659                 #row.itemR(psys, "vertex_group_rotation_negate", text="")
660                 
661                 #row = layout.row()
662                 #row.itemR(psys, "vertex_group_field")
663                 #row.itemR(psys, "vertex_group_field_negate", text="")
664                 
665 bpy.types.register(PARTICLE_PT_particles)
666 bpy.types.register(PARTICLE_PT_cache)
667 bpy.types.register(PARTICLE_PT_emission)
668 bpy.types.register(PARTICLE_PT_initial)
669 bpy.types.register(PARTICLE_PT_physics)
670 bpy.types.register(PARTICLE_PT_render)
671 bpy.types.register(PARTICLE_PT_draw)
672 bpy.types.register(PARTICLE_PT_children)
673 bpy.types.register(PARTICLE_PT_vertexgroups)