693b737e1aacca99f61dd86c53e7c15bdce92ba3
[blender.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         return psys.settings.type in ('EMITTER', 'REACTOR', 'HAIR')
11
12 class ParticleButtonsPanel(bpy.types.Panel):
13         __space_type__ = "BUTTONS_WINDOW"
14         __region_type__ = "WINDOW"
15         __context__ = "particle"
16
17         def poll(self, context):
18                 return particle_panel_poll(context)
19
20 class PARTICLE_PT_particles(ParticleButtonsPanel):
21         __idname__= "PARTICLE_PT_particles"
22         __label__ = "ParticleSystem"
23
24         def poll(self, context):
25                 return (context.particle_system != None)
26         
27         def draw(self, context):
28                 layout = self.layout
29
30                 psys = context.particle_system
31                 part = psys.settings
32                 
33                 #row = layout.row()
34                 #row.itemL(text="Particle system datablock")
35                 #row.itemL(text="Viewport")
36                 #row.itemL(text="Render")
37                 
38                 ptype = psys.settings.type
39                 
40                 if ptype not in ('EMITTER', 'REACTOR', 'HAIR'):
41                         layout.itemL(text="No settings for fluid particles")
42                         return
43                 
44                 row = layout.row()
45                 row.enabled = particle_panel_enabled(psys)
46                 row.itemR(part, "type")
47                 row.itemR(psys, "seed")
48                 
49                 row = layout.row()
50                 if part.type=='HAIR':
51                         if psys.editable==True:
52                                 row.itemO("PARTICLE_OT_editable_set", text="Free Edit")
53                         else:
54                                 row.itemO("PARTICLE_OT_editable_set", text="Make Editable")
55                         subrow = row.row()
56                         subrow.enabled = particle_panel_enabled(psys)
57                         subrow.itemR(part, "hair_step")
58                 elif part.type=='REACTOR':
59                         row.itemR(psys, "reactor_target_object")
60                         row.itemR(psys, "reactor_target_particle_system", text="Particle System")
61                 
62 class PARTICLE_PT_emission(ParticleButtonsPanel):
63         __idname__= "PARTICLE_PT_emission"
64         __label__ = "Emission"
65         
66         def draw(self, context):
67                 layout = self.layout
68
69                 psys = context.particle_system
70                 part = psys.settings
71                 
72                 layout.enabled = particle_panel_enabled(psys)
73                 
74                 row = layout.row()
75                 #col.itemL(text="TODO: Rate instead of amount")
76                 row.itemR(part, "amount")
77                 row.itemL(text="")
78                 
79                 split = layout.split()
80                 
81                 col = split.column(align=True)
82                 col.itemR(part, "start")
83                 col.itemR(part, "end")
84
85                 col = split.column(align=True)
86                 col.itemR(part, "lifetime")
87                 col.itemR(part, "random_lifetime", slider=True)
88                 
89 class PARTICLE_PT_cache(ParticleButtonsPanel):
90         __idname__= "PARTICLE_PT_cache"
91         __label__ = "Cache"
92         
93         def poll(self, context):
94                 psys = context.particle_system
95                 if psys==None:  return False
96                 return psys.settings.type in ('EMITTER', 'REACTOR')
97
98         def draw(self, context):
99                 layout = self.layout
100
101                 psys = context.particle_system
102                 part = psys.settings
103                 cache = psys.point_cache
104                 
105                 #if cache.baked==True:
106                         #layout.itemO("PARTICLE_OT_free_bake", text="BAKE")
107                 #else:
108                 row = layout.row()
109                         #row.itemO("PARTICLE_OT_bake", text="BAKE")
110                 row.itemR(cache, "start_frame")
111                 row.itemR(cache, "end_frame")
112                         
113                         #layout.row().itemL(text="No simulation frames in disk cache.")
114                 
115                 
116 class PARTICLE_PT_initial(ParticleButtonsPanel):
117         __idname__= "PARTICLE_PT_initial"
118         __label__ = "Initial values"
119
120         def draw(self, context):
121                 layout = self.layout
122
123                 psys = context.particle_system
124                 part = psys.settings
125                 
126                 layout.enabled = particle_panel_enabled(psys)
127                 
128                 layout.row().itemL(text="Location from:")
129                 
130                 box = layout.box()
131                 row = box.row()
132                 row.itemR(part, "trand")
133                 
134                 col = row.column()
135                 col.row().itemR(part, "emit_from", expand=True)
136                 
137                 if part.emit_from=='FACE' or part.emit_from=='VOLUME':
138                         row = box.row()
139
140                         if part.distribution!='GRID':
141                                 row.itemR(part, "even_distribution")
142                         else:
143                                 row.itemL(text="")
144                                 
145                         row.itemR(part, "distribution", expand=True)
146                         
147                         row = box.row()
148
149                         if part.distribution=='JIT':
150                                 row.itemR(part, "userjit", text="Particles/Face")
151                                 row.itemR(part, "jitter_factor", text="Jittering Amount", slider=True)
152                         elif part.distribution=='GRID':
153                                 row.itemR(part, "grid_resolution")
154
155                 #layout.row().itemL(text="")
156                                 
157                 layout.row().itemL(text="Velocity:")
158                 box = layout.box()
159                 row = box.row()
160                 col = row.column()
161                 col.itemR(part, "normal_factor")
162                 if part.emit_from=='PARTICLE':
163                         col.itemR(part, "particle_factor")
164                 else:
165                         col.itemR(part, "object_factor", slider=True)
166                 col.itemR(part, "random_factor")
167                 
168                 col = row.column(align=True)
169                 col.itemL(text="TODO:")
170                 col.itemL(text="Object aligned")
171                 col.itemL(text="direction: X, Y, Z")
172                 
173                 row = box.row()
174                 col = row.column(align=True)
175                 col.itemR(part, "tangent_factor")
176                 col.itemR(part, "tangent_phase", slider=True)
177                 
178                 col = row.column(align=True)
179                 if part.type=='REACTOR':
180                         col.itemR(part, "reactor_factor")
181                         col.itemR(part, "reaction_shape", slider=True)
182                 else:
183                         col.itemL(text="")
184                 
185                 layout.row().itemL(text="Rotation:")
186                 box = layout.box()
187                 box.row().itemR(part, "rotation_dynamic")
188                 
189                 row = box.row()
190                 col = row.column(align=True)
191                 col.itemR(part, "rotation_mode", text="")
192                 col.itemR(part, "random_rotation_factor", slider=True)
193                 col = row.column(align=True)
194                 col.itemR(part, "phase_factor", slider=True)
195                 col.itemR(part, "random_phase_factor", text="Random", slider=True)
196                 
197                 
198                 layout.row().itemL(text="Angular velocity:")
199
200                 box = layout.box()
201                 row = box.row()
202                 row.itemR(part, "angular_velocity_mode", expand=True)
203                 row.itemR(part, "angular_velocity_factor", text="")
204                 
205 class PARTICLE_PT_physics(ParticleButtonsPanel):
206         __idname__= "PARTICLE_PT_physics"
207         __label__ = "Physics"
208
209         def draw(self, context):
210                 layout = self.layout
211
212                 psys = context.particle_system
213                 part = psys.settings
214                 
215                 layout.enabled = layout.enabled = particle_panel_enabled(psys)
216                 
217                 layout.itemR(part, "effector_group")
218                 
219                 layout.itemL(text="General:")
220                 box = layout.box()
221                 row = box.row()
222                 col = row.column(align=True)
223                 col.itemR(part, "particle_size")
224                 col.itemR(part, "random_size", slider=True)
225                 col = row.column(align=True)
226                 col.itemR(part, "mass")
227                 col.itemR(part, "sizemass", text="Multiply mass with size")
228                 
229                 layout.row().itemL(text="")
230                 
231                 row = layout.row()
232                 row.itemL(text="Physics Type:")
233                 row.itemR(part, "physics_type", expand=True)
234                 
235                 if part.physics_type != 'NO':
236                         box = layout.box()
237                         row = box.row()
238                 
239                 if part.physics_type == 'NEWTON':
240                         row.itemR(part, "integrator")
241                         row = box.row()
242                         col = row.column(align=True)
243                         col.itemL(text="Forces:")
244                         col.itemR(part, "brownian_factor")
245                         col.itemR(part, "drag_factor", slider=True)
246                         col.itemR(part, "damp_factor", slider=True)
247                         
248                         row.column().itemR(part, "acceleration")
249                 elif part.physics_type == 'KEYED':
250                         row.itemR(psys, "keyed_first")
251                         if psys.keyed_first==True:
252                                 row.itemR(psys, "timed_keys", text="Key timing")
253                         else:
254                                 row.itemR(part, "keyed_time")
255                         
256                         row = box.row()
257                         row.itemL(text="Next key from object:")
258                         row.itemR(psys, "keyed_object", text="")
259                         row.itemR(psys, "keyed_particle_system")
260                 
261                 if part.physics_type=='NEWTON' or part.physics_type=='BOIDS':
262                         row = box.row()
263                         row.itemR(part, "size_deflect")
264                         row.itemR(part, "die_on_collision")
265                         row.itemR(part, "sticky")
266
267 class PARTICLE_PT_render(ParticleButtonsPanel):
268         __idname__= "PARTICLE_PT_render"
269         __label__ = "Render"
270         
271         def poll(self, context):
272                 return (context.particle_system != None)
273                 
274         def draw(self, context):
275                 layout = self.layout
276
277                 psys = context.particle_system
278                 part = psys.settings
279                 
280                 row = layout.row()
281                 row.itemR(part, "material")
282                 col = row.column()
283                 col.itemR(part, "emitter");
284                 col.itemR(part, "parent");
285                 col = row.column()
286                 col.itemR(part, "unborn");
287                 col.itemR(part, "died");
288                 
289                 row = layout.row()
290                 row.itemR(part, "ren_as", expand=True)
291                 
292                 row = layout.row(align=True)
293                 
294                 if part.ren_as == 'LINE':
295                         row.itemR(part, "line_length_tail")
296                         row.itemR(part, "line_length_head")
297                         row.itemR(part, "velocity_length")
298                 elif part.ren_as == 'PATH':
299                 
300                         if (part.type!='HAIR' and psys.point_cache.baked==False):
301                                 box = layout.box()
302                                 box.itemL(text="Baked or keyed particles needed for correct rendering.")
303                                 return
304                                 
305                         row.itemR(part, "hair_bspline")
306                         row.itemR(part, "render_step", text="Steps")
307                         
308                         row = layout.row()
309                         row.itemR(part, "abs_length")
310                         col = row.column(align=True)
311                         col.itemR(part, "absolute_length")
312                         col.itemR(part, "random_length", slider=True)
313                         
314                         #row = layout.row()
315                         #row.itemR(part, "timed_path")
316                         #col = row.column(align=True)
317                         #col.active = part.timed_path == True
318                         #col.itemR(part, "line_length_tail", text="Start")
319                         #col.itemR(part, "line_length_head", text="End")
320                         
321                         row = layout.row()
322                         col = row.column()
323                         col.itemR(part, "render_strand")
324                         
325                         subrow = col.row()
326                         subrow.active = part.render_strand == False
327                         subrow.itemR(part, "render_adaptive")
328                         col = row.column(align=True)
329                         subrow = col.row()
330                         subrow.active = part.render_adaptive or part.render_strand == True
331                         subrow.itemR(part, "adaptive_angle")
332                         subrow = col.row()
333                         subrow.active = part.render_adaptive == True and part.render_strand == False
334                         subrow.itemR(part, "adaptive_pix")
335                         
336                         if part.type=='HAIR' and part.render_strand==True and part.child_type=='FACES':
337                                 layout.itemR(part, "enable_simplify")
338                                 if part.enable_simplify==True:
339                                         box = layout.box()
340                                         row = box.row()
341                                         row.itemR(part, "simplify_refsize")
342                                         row.itemR(part, "simplify_rate")
343                                         row.itemR(part, "simplify_transition")
344                                         row = box.row()
345                                         row.itemR(part, "viewport")
346                                         subrow = row.row()
347                                         subrow.active = part.viewport==True
348                                         subrow.itemR(part, "simplify_viewport")
349                         
350
351                 elif part.ren_as == 'OBJECT':
352                         row.itemR(part, "dupli_object")
353                 elif part.ren_as == 'GROUP':
354                         split = layout.split()
355                         col = split.column()
356                         row = col.row()
357                         row.itemR(part, "whole_group")
358                         subcol = row.column()
359                         subcol.active = part.whole_group == False
360                         subcol.itemR(part, "rand_group")
361                         split.column().itemR(part, "dupli_group", text="")
362                 elif part.ren_as == 'BILLBOARD':
363                         row.itemL(text="Align:")
364                         row.itemR(part, "billboard_lock", text="Lock")
365                         row = layout.row()
366                         row.itemR(part, "billboard_align", expand=True)
367                         row = layout.row()
368                         row.itemR(part, "billboard_object")
369                 
370                         row = layout.row()
371                         col = row.column(align=True)
372                         col.itemL(text="Tilt:")
373                         col.itemR(part, "billboard_tilt", text="Angle", slider=True)
374                         col.itemR(part, "billboard_random_tilt", slider=True)
375                         col = row.column()
376                         col.itemR(part, "billboard_offset")
377                         
378                         row = layout.row()
379                         row.itemR(psys, "billboard_normal_uv")
380                         row = layout.row()
381                         row.itemR(psys, "billboard_time_index_uv")
382                         
383                         row = layout.row()
384                         row.itemL(text="Split uv's:")
385                         row.itemR(part, "billboard_uv_split", text="Number of splits")
386                         row = layout.row()
387                         row.itemR(psys, "billboard_split_uv")
388                         row = layout.row()
389                         row.itemL(text="Animate:")
390                         row.itemR(part, "billboard_animation", expand=True)
391                         row.itemL(text="Offset:")
392                         row.itemR(part, "billboard_split_offset", expand=True)
393                 
394 class PARTICLE_PT_draw(ParticleButtonsPanel):
395         __idname__= "PARTICLE_PT_draw"
396         __label__ = "Draw"
397         
398         def poll(self, context):
399                 return (context.particle_system != None)
400         
401         def draw(self, context):
402                 layout = self.layout
403
404                 psys = context.particle_system
405                 part = psys.settings
406                 
407                 row = layout.row()
408                 row.itemR(part, "draw_as", expand=True)
409                 
410                 if part.draw_as=='NONE' or (part.ren_as=='NONE' and part.draw_as=='RENDER'):
411                         return
412                         
413                 path = (part.ren_as=='PATH' and part.draw_as=='RENDER') or part.draw_as=='PATH'
414                         
415                 if path and part.type!='HAIR' and psys.point_cache.baked==False:
416                         box = layout.box()
417                         box.itemL(text="Baked or keyed particles needed for correct drawing.")
418                         return
419                 
420                 row = layout.row()
421                 row.itemR(part, "display", slider=True)
422                 if part.draw_as!='RENDER' or part.ren_as=='HALO':
423                         row.itemR(part, "draw_size")
424                 else:
425                         row.itemL(text="")
426                 
427                 row = layout.row()
428                 col = row.column()
429                 col.itemR(part, "show_size")
430                 col.itemR(part, "velocity")
431                 col.itemR(part, "num")
432                 if part.physics_type == 'BOIDS':
433                         col.itemR(part, "draw_health")
434                 
435                 col = row.column()
436                 if (path):
437                         box = col.box()                         
438                         box.itemR(part, "draw_step")
439                 else:
440                         col.itemR(part, "material_color", text="Use material color")
441                         subcol = col.column()
442                         subcol.active = part.material_color==False
443                         #subcol.itemL(text="color")
444                         #subcol.itemL(text="Override material color")
445                         
446
447 class PARTICLE_PT_children(ParticleButtonsPanel):
448         __idname__= "PARTICLE_PT_children"
449         __label__ = "Children"
450
451         def draw(self, context):
452                 layout = self.layout
453
454                 psys = context.particle_system
455                 part = psys.settings
456                 
457                 layout.row().itemR(part, "child_type", expand=True)
458                 
459                 if part.child_type=='NONE':
460                         return
461                 
462                 row = layout.row()
463                 
464                 col = row.column(align=True)
465                 col.itemR(part, "child_nbr", text="Draw")
466                 col.itemR(part, "rendered_child_nbr", text="Render")
467                 
468                 col = row.column(align=True)
469                 
470                 if part.child_type=='FACES':
471                         col.itemR(part, "virtual_parents", slider=True)
472                 else:
473                         col.itemR(part, "child_radius", text="Radius")
474                         col.itemR(part, "child_roundness", text="Roundness", slider=True)
475                 
476                         col = row.column(align=True)
477                         col.itemR(part, "child_size", text="Size")
478                         col.itemR(part, "child_random_size", text="Random")
479                 
480                 layout.row().itemL(text="Effects:")
481                 
482                 row = layout.row()
483                 
484                 col = row.column(align=True)
485                 col.itemR(part, "clump_factor", slider=True)
486                 col.itemR(part, "clumppow", slider=True)
487                 
488                 col = row.column(align=True)
489                 col.itemR(part, "rough_endpoint")
490                 col.itemR(part, "rough_end_shape")
491
492                 row = layout.row()
493                 
494                 col = row.column(align=True)
495                 col.itemR(part, "rough1")
496                 col.itemR(part, "rough1_size")
497
498                 col = row.column(align=True)
499                 col.itemR(part, "rough2")
500                 col.itemR(part, "rough2_size")
501                 col.itemR(part, "rough2_thres", slider=True)
502                 
503                 layout.row().itemL(text="Kink:")
504                 layout.row().itemR(part, "kink", expand=True)
505                 
506                 row = layout.row()
507                 row.itemR(part, "kink_amplitude")
508                 row.itemR(part, "kink_frequency")
509                 row.itemR(part, "kink_shape", slider=True)
510
511                                 
512                 
513 class PARTICLE_PT_vertexgroups(ParticleButtonsPanel):
514         __idname__= "PARTICLE_PT_vertexgroups"
515         __label__ = "Vertexgroups"
516
517         def draw(self, context):
518                 layout = self.layout
519
520                 psys = context.particle_system
521                 part = psys.settings
522                 
523                 layout.itemL(text="Nothing here yet.")
524
525                 #row = layout.row()
526                 #row.itemL(text="Vertex Group")
527                 #row.itemL(text="Negate")
528
529                 
530                 #row = layout.row()
531                 #row.itemR(psys, "vertex_group_density")
532                 #row.itemR(psys, "vertex_group_density_negate", text="")
533                 
534                 #row = layout.row()
535                 #row.itemR(psys, "vertex_group_velocity")
536                 #row.itemR(psys, "vertex_group_velocity_negate", text="")
537                 
538                 #row = layout.row()
539                 #row.itemR(psys, "vertex_group_length")
540                 #row.itemR(psys, "vertex_group_length_negate", text="")
541                 
542                 #row = layout.row()
543                 #row.itemR(psys, "vertex_group_clump")
544                 #row.itemR(psys, "vertex_group_clump_negate", text="")
545                 
546                 #row = layout.row()
547                 #row.itemR(psys, "vertex_group_kink")
548                 #row.itemR(psys, "vertex_group_kink_negate", text="")
549                 
550                 #row = layout.row()
551                 #row.itemR(psys, "vertex_group_roughness1")
552                 #row.itemR(psys, "vertex_group_roughness1_negate", text="")
553                 
554                 #row = layout.row()
555                 #row.itemR(psys, "vertex_group_roughness2")
556                 #row.itemR(psys, "vertex_group_roughness2_negate", text="")
557                 
558                 #row = layout.row()
559                 #row.itemR(psys, "vertex_group_roughness_end")
560                 #row.itemR(psys, "vertex_group_roughness_end_negate", text="")
561
562                 #row = layout.row()
563                 #row.itemR(psys, "vertex_group_size")
564                 #row.itemR(psys, "vertex_group_size_negate", text="")
565                 
566                 #row = layout.row()
567                 #row.itemR(psys, "vertex_group_tangent")
568                 #row.itemR(psys, "vertex_group_tangent_negate", text="")
569                 
570                 #row = layout.row()
571                 #row.itemR(psys, "vertex_group_rotation")
572                 #row.itemR(psys, "vertex_group_rotation_negate", text="")
573                 
574                 #row = layout.row()
575                 #row.itemR(psys, "vertex_group_field")
576                 #row.itemR(psys, "vertex_group_field_negate", text="")
577                 
578 bpy.types.register(PARTICLE_PT_particles)
579 bpy.types.register(PARTICLE_PT_cache)
580 bpy.types.register(PARTICLE_PT_emission)
581 bpy.types.register(PARTICLE_PT_initial)
582 bpy.types.register(PARTICLE_PT_physics)
583 bpy.types.register(PARTICLE_PT_render)
584 bpy.types.register(PARTICLE_PT_draw)
585 bpy.types.register(PARTICLE_PT_children)
586 bpy.types.register(PARTICLE_PT_vertexgroups)
587