rna data path names which are more likely to break animations.
[blender-staging.git] / release / scripts / ui / properties_particle.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20 import bpy
21 from rna_prop_ui import PropertyPanel
22
23 from properties_physics_common import point_cache_ui
24 from properties_physics_common import effector_weights_ui
25 from properties_physics_common import basic_force_field_settings_ui
26 from properties_physics_common import basic_force_field_falloff_ui
27
28
29 def particle_panel_enabled(context, psys):
30     return (psys.point_cache.is_baked is False) and (not psys.is_edited) and (not context.particle_system_editable)
31
32
33 def particle_panel_poll(cls, context):
34     psys = context.particle_system
35     engine = context.scene.render.engine
36     if psys is None:
37         return False
38     if psys.settings is None:
39         return False
40     return psys.settings.type in ('EMITTER', 'REACTOR', 'HAIR') and (engine in cls.COMPAT_ENGINES)
41
42
43 class ParticleButtonsPanel():
44     bl_space_type = 'PROPERTIES'
45     bl_region_type = 'WINDOW'
46     bl_context = "particle"
47
48     @classmethod
49     def poll(cls, context):
50         return particle_panel_poll(cls, context)
51
52
53 class PARTICLE_PT_context_particles(ParticleButtonsPanel, bpy.types.Panel):
54     bl_label = ""
55     bl_show_header = False
56     COMPAT_ENGINES = {'BLENDER_RENDER'}
57
58     @classmethod
59     def poll(cls, context):
60         engine = context.scene.render.engine
61         return (context.particle_system or context.object) and (engine in cls.COMPAT_ENGINES)
62
63     def draw(self, context):
64         layout = self.layout
65
66         ob = context.object
67         psys = context.particle_system
68
69         if ob:
70             row = layout.row()
71
72             row.template_list(ob, "particle_systems", ob, "active_particle_system_index", rows=2)
73
74             col = row.column(align=True)
75             col.operator("object.particle_system_add", icon='ZOOMIN', text="")
76             col.operator("object.particle_system_remove", icon='ZOOMOUT', text="")
77
78         if psys and not psys.settings:
79             split = layout.split(percentage=0.32)
80
81             col = split.column()
82             col.label(text="Name:")
83             col.label(text="Settings:")
84
85             col = split.column()
86             col.prop(psys, "name", text="")
87             col.template_ID(psys, "settings", new="particle.new")
88         elif psys:
89             part = psys.settings
90
91             split = layout.split(percentage=0.32)
92             col = split.column()
93             col.label(text="Name:")
94             if part.type in ('EMITTER', 'REACTOR', 'HAIR'):
95                 col.label(text="Settings:")
96                 col.label(text="Type:")
97
98             col = split.column()
99             col.prop(psys, "name", text="")
100             if part.type in ('EMITTER', 'REACTOR', 'HAIR'):
101                 col.template_ID(psys, "settings", new="particle.new")
102
103             #row = layout.row()
104             #row.label(text="Viewport")
105             #row.label(text="Render")
106
107             if part:
108                 if part.type not in ('EMITTER', 'REACTOR', 'HAIR'):
109                     layout.label(text="No settings for fluid particles")
110                     return
111
112                 row = col.row()
113                 row.enabled = particle_panel_enabled(context, psys)
114                 row.prop(part, "type", text="")
115                 row.prop(psys, "seed")
116
117                 split = layout.split(percentage=0.65)
118                 if part.type == 'HAIR':
119                     if psys.is_edited:
120                         split.operator("particle.edited_clear", text="Free Edit")
121                     else:
122                         split.label(text="")
123                     row = split.row()
124                     row.enabled = particle_panel_enabled(context, psys)
125                     row.prop(part, "hair_step")
126                     if psys.is_edited:
127                         if psys.is_global_hair:
128                             layout.operator("particle.connect_hair")
129                             layout.label(text="Hair is disconnected.")
130                         else:
131                             layout.operator("particle.disconnect_hair")
132                             layout.label(text="")
133                 elif part.type == 'REACTOR':
134                     split.enabled = particle_panel_enabled(context, psys)
135                     split.prop(psys, "reactor_target_object")
136                     split.prop(psys, "reactor_target_particle_system", text="Particle System")
137
138
139 class PARTICLE_PT_emission(ParticleButtonsPanel, bpy.types.Panel):
140     bl_label = "Emission"
141     COMPAT_ENGINES = {'BLENDER_RENDER'}
142
143     @classmethod
144     def poll(cls, context):
145         if particle_panel_poll(PARTICLE_PT_emission, context):
146             return not context.particle_system.point_cache.use_external
147         else:
148             return False
149
150     def draw(self, context):
151         layout = self.layout
152
153         psys = context.particle_system
154         part = psys.settings
155
156         layout.enabled = particle_panel_enabled(context, psys) and not psys.has_multiple_caches
157
158         row = layout.row()
159         row.active = part.distribution != 'GRID'
160         row.prop(part, "amount")
161
162         if part.type != 'HAIR':
163             split = layout.split()
164
165             col = split.column(align=True)
166             col.prop(part, "frame_start")
167             col.prop(part, "frame_end")
168
169             col = split.column(align=True)
170             col.prop(part, "lifetime")
171             col.prop(part, "lifetime_random", slider=True)
172
173         layout.row().label(text="Emit From:")
174
175         row = layout.row()
176         row.prop(part, "emit_from", expand=True)
177
178         row = layout.row()
179         row.prop(part, "trand")
180         if part.distribution != 'GRID':
181             row.prop(part, "use_even_distribution")
182
183         if part.emit_from == 'FACE' or part.emit_from == 'VOLUME':
184             row = layout.row()
185
186             row.prop(part, "distribution", expand=True)
187
188             row = layout.row()
189
190             if part.distribution == 'JIT':
191                 row.prop(part, "userjit", text="Particles/Face")
192                 row.prop(part, "jitter_factor", text="Jittering Amount", slider=True)
193             elif part.distribution == 'GRID':
194                 row.prop(part, "grid_resolution")
195
196
197 class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, bpy.types.Panel):
198     bl_label = "Hair dynamics"
199     bl_default_closed = True
200     COMPAT_ENGINES = {'BLENDER_RENDER'}
201
202     @classmethod
203     def poll(cls, context):
204         psys = context.particle_system
205         engine = context.scene.render.engine
206         if psys is None:
207             return False
208         if psys.settings is None:
209             return False
210         return psys.settings.type == 'HAIR' and (engine in cls.COMPAT_ENGINES)
211
212     def draw_header(self, context):
213         #cloth = context.cloth.collision_settings
214
215         #self.layout.active = cloth_panel_enabled(context.cloth)
216         #self.layout.prop(cloth, "use_collision", text="")
217         psys = context.particle_system
218         self.layout.prop(psys, "use_hair_dynamics", text="")
219
220     def draw(self, context):
221         layout = self.layout
222
223         psys = context.particle_system
224
225         if not psys.cloth:
226             return
227
228         #part = psys.settings
229         cloth = psys.cloth.settings
230
231         layout.enabled = psys.use_hair_dynamics
232
233         split = layout.split()
234
235         col = split.column()
236         col.label(text="Material:")
237         sub = col.column(align=True)
238         sub.prop(cloth, "pin_stiffness", text="Stiffness")
239         sub.prop(cloth, "mass")
240         sub.prop(cloth, "bending_stiffness", text="Bending")
241         sub.prop(cloth, "internal_friction", slider=True)
242         sub.prop(cloth, "collider_friction", slider=True)
243
244         col = split.column()
245
246         col.label(text="Damping:")
247         sub = col.column(align=True)
248         sub.prop(cloth, "spring_damping", text="Spring")
249         sub.prop(cloth, "air_damping", text="Air")
250
251         col.label(text="Quality:")
252         col.prop(cloth, "quality", text="Steps", slider=True)
253
254
255 class PARTICLE_PT_cache(ParticleButtonsPanel, bpy.types.Panel):
256     bl_label = "Cache"
257     bl_default_closed = True
258     COMPAT_ENGINES = {'BLENDER_RENDER'}
259
260     @classmethod
261     def poll(cls, context):
262         psys = context.particle_system
263         engine = context.scene.render.engine
264         if psys is None:
265             return False
266         if psys.settings is None:
267             return False
268         phystype = psys.settings.physics_type
269         if phystype == 'NO' or phystype == 'KEYED':
270             return False
271         return (psys.settings.type in ('EMITTER', 'REACTOR') or (psys.settings.type == 'HAIR' and psys.use_hair_dynamics)) and engine in cls.COMPAT_ENGINES
272
273     def draw(self, context):
274         psys = context.particle_system
275
276         point_cache_ui(self, context, psys.point_cache, True, 'HAIR' if psys.use_hair_dynamics else 'PSYS')
277
278
279 class PARTICLE_PT_velocity(ParticleButtonsPanel, bpy.types.Panel):
280     bl_label = "Velocity"
281     COMPAT_ENGINES = {'BLENDER_RENDER'}
282
283     @classmethod
284     def poll(cls, context):
285         if particle_panel_poll(PARTICLE_PT_velocity, context):
286             psys = context.particle_system
287             return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.use_external
288         else:
289             return False
290
291     def draw(self, context):
292         layout = self.layout
293
294         psys = context.particle_system
295         part = psys.settings
296
297         layout.enabled = particle_panel_enabled(context, psys)
298
299         split = layout.split()
300
301         sub = split.column()
302         sub.label(text="Emitter Geometry:")
303         sub.prop(part, "normal_factor")
304         subsub = sub.column(align=True)
305         subsub.prop(part, "tangent_factor")
306         subsub.prop(part, "tangent_phase", slider=True)
307
308         sub = split.column()
309         sub.label(text="Emitter Object")
310         sub.prop(part, "object_align_factor", text="")
311
312         layout.row().label(text="Other:")
313         split = layout.split()
314         sub = split.column()
315         if part.emit_from == 'PARTICLE':
316             sub.prop(part, "particle_factor")
317         else:
318             sub.prop(part, "object_factor", slider=True)
319         sub = split.column()
320         sub.prop(part, "factor_random")
321
322         #if part.type=='REACTOR':
323         #    sub.prop(part, "reactor_factor")
324         #    sub.prop(part, "reaction_shape", slider=True)
325
326
327 class PARTICLE_PT_rotation(ParticleButtonsPanel, bpy.types.Panel):
328     bl_label = "Rotation"
329     COMPAT_ENGINES = {'BLENDER_RENDER'}
330
331     @classmethod
332     def poll(cls, context):
333         if particle_panel_poll(PARTICLE_PT_rotation, context):
334             psys = context.particle_system
335             return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.use_external
336         else:
337             return False
338
339     def draw(self, context):
340         layout = self.layout
341
342         psys = context.particle_system
343         part = psys.settings
344
345         layout.enabled = particle_panel_enabled(context, psys)
346
347         split = layout.split()
348         split.label(text="Initial Rotation:")
349         split.prop(part, "use_dynamic_rotation")
350         split = layout.split()
351
352         sub = split.column(align=True)
353         sub.prop(part, "rotation_mode", text="")
354         sub.prop(part, "rotation_factor_random", slider=True, text="Random")
355
356         sub = split.column(align=True)
357         sub.prop(part, "phase_factor", slider=True)
358         sub.prop(part, "phase_factor_random", text="Random", slider=True)
359
360         layout.row().label(text="Angular Velocity:")
361         layout.row().prop(part, "angular_velocity_mode", expand=True)
362         split = layout.split()
363
364         sub = split.column()
365
366         if part.angular_velocity_mode != 'NONE':
367             sub.prop(part, "angular_velocity_factor", text="")
368
369
370 class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
371     bl_label = "Physics"
372     COMPAT_ENGINES = {'BLENDER_RENDER'}
373
374     @classmethod
375     def poll(cls, context):
376         if particle_panel_poll(PARTICLE_PT_physics, context):
377             return not context.particle_system.point_cache.use_external
378         else:
379             return False
380
381     def draw(self, context):
382         layout = self.layout
383
384         psys = context.particle_system
385         part = psys.settings
386
387         layout.enabled = particle_panel_enabled(context, psys)
388
389         row = layout.row()
390         row.prop(part, "physics_type", expand=True)
391
392         row = layout.row()
393         col = row.column(align=True)
394         col.prop(part, "particle_size")
395         col.prop(part, "size_random", slider=True)
396
397         if part.physics_type != 'NO':
398             col = row.column(align=True)
399             col.prop(part, "mass")
400             col.prop(part, "use_multiply_size_mass", text="Multiply mass with size")
401
402         if part.physics_type == 'NEWTON':
403             split = layout.split()
404             sub = split.column()
405
406             sub.label(text="Forces:")
407             sub.prop(part, "brownian_factor")
408             sub.prop(part, "drag_factor", slider=True)
409             sub.prop(part, "damping", slider=True)
410             sub = split.column()
411             sub.label(text="Integration:")
412             sub.prop(part, "integrator", text="")
413             sub.prop(part, "time_tweak")
414             sub.prop(part, "subframes")
415             sub = layout.row()
416             sub.prop(part, "use_size_deflect")
417             sub.prop(part, "use_die_on_collision")
418
419         elif part.physics_type == 'FLUID':
420             fluid = part.fluid
421             split = layout.split()
422             sub = split.column()
423
424             sub.label(text="Forces:")
425             sub.prop(part, "brownian_factor")
426             sub.prop(part, "drag_factor", slider=True)
427             sub.prop(part, "damping", slider=True)
428             sub = split.column()
429             sub.label(text="Integration:")
430             sub.prop(part, "integrator", text="")
431             sub.prop(part, "time_tweak")
432             sub.prop(part, "subframes")
433             sub = layout.row()
434             sub.prop(part, "use_size_deflect")
435             sub.prop(part, "use_die_on_collision")
436
437             split = layout.split()
438             sub = split.column()
439             sub.label(text="Fluid Interaction:")
440             sub.prop(fluid, "fluid_radius", slider=True)
441             sub.prop(fluid, "stiffness")
442             sub.prop(fluid, "stiffness_near")
443             sub.prop(fluid, "rest_density")
444
445             sub.label(text="Viscosity:")
446             sub.prop(fluid, "viscosity_omega", text="Linear")
447             sub.prop(fluid, "viscosity_beta", text="Square")
448
449             sub = split.column()
450
451             sub.label(text="Springs:")
452             sub.prop(fluid, "spring_force", text="Force", slider=True)
453             sub.prop(fluid, "rest_length", slider=True)
454             layout.label(text="Multiple fluids interactions:")
455
456             sub.label(text="Buoyancy:")
457             sub.prop(fluid, "buoyancy", slider=True)
458
459         elif part.physics_type == 'KEYED':
460             split = layout.split()
461             sub = split.column()
462
463             row = layout.row()
464             col = row.column()
465             col.active = not psys.use_keyed_timing
466             col.prop(part, "keyed_loops", text="Loops")
467             row.prop(psys, "use_keyed_timing", text="Use Timing")
468
469             layout.label(text="Keys:")
470         elif part.physics_type == 'BOIDS':
471             boids = part.boids
472
473
474             row = layout.row()
475             row.prop(boids, "use_flight")
476             row.prop(boids, "use_land")
477             row.prop(boids, "use_climb")
478
479             split = layout.split()
480
481             sub = split.column()
482             col = sub.column(align=True)
483             col.active = boids.use_flight
484             col.prop(boids, "air_speed_max")
485             col.prop(boids, "air_speed_min", slider=True)
486             col.prop(boids, "air_acc_max", slider=True)
487             col.prop(boids, "air_ave_max", slider=True)
488             col.prop(boids, "air_personal_space")
489             row = col.row()
490             row.active = (boids.use_land or boids.allow_climb) and boids.allow_flight
491             row.prop(boids, "land_smooth")
492
493             sub = split.column()
494             col = sub.column(align=True)
495             col.active = boids.use_land or boids.allow_climb
496             col.prop(boids, "land_speed_max")
497             col.prop(boids, "land_jump_speed")
498             col.prop(boids, "land_acc_max", slider=True)
499             col.prop(boids, "land_ave_max", slider=True)
500             col.prop(boids, "land_personal_space")
501             col.prop(boids, "land_stick_force")
502
503             row = layout.row()
504
505             col = row.column(align=True)
506             col.label(text="Battle:")
507             col.prop(boids, "health")
508             col.prop(boids, "strength")
509             col.prop(boids, "aggression")
510             col.prop(boids, "accuracy")
511             col.prop(boids, "range")
512
513             col = row.column()
514             col.label(text="Misc:")
515             col.prop(boids, "bank", slider=True)
516             col.prop(boids, "height", slider=True)
517
518         if part.physics_type == 'KEYED' or part.physics_type == 'BOIDS' or part.physics_type == 'FLUID':
519             if part.physics_type == 'BOIDS':
520                 layout.label(text="Relations:")
521
522             row = layout.row()
523             row.template_list(psys, "targets", psys, "active_particle_target_index")
524
525             col = row.column()
526             sub = col.row()
527             subsub = sub.column(align=True)
528             subsub.operator("particle.new_target", icon='ZOOMIN', text="")
529             subsub.operator("particle.target_remove", icon='ZOOMOUT', text="")
530             sub = col.row()
531             subsub = sub.column(align=True)
532             subsub.operator("particle.target_move_up", icon='MOVE_UP_VEC', text="")
533             subsub.operator("particle.target_move_down", icon='MOVE_DOWN_VEC', text="")
534
535             key = psys.active_particle_target
536             if key:
537                 row = layout.row()
538                 if part.physics_type == 'KEYED':
539                     col = row.column()
540                     #doesn't work yet
541                     #col.red_alert = key.valid
542                     col.prop(key, "object", text="")
543                     col.prop(key, "system", text="System")
544                     col = row.column()
545                     col.active = psys.use_keyed_timing
546                     col.prop(key, "time")
547                     col.prop(key, "duration")
548                 elif part.physics_type == 'BOIDS':
549                     sub = row.row()
550                     #doesn't work yet
551                     #sub.red_alert = key.valid
552                     sub.prop(key, "object", text="")
553                     sub.prop(key, "system", text="System")
554
555                     layout.prop(key, "alliance", expand=True)
556                 elif part.physics_type == 'FLUID':
557                     sub = row.row()
558                     #doesn't work yet
559                     #sub.red_alert = key.valid
560                     sub.prop(key, "object", text="")
561                     sub.prop(key, "system", text="System")
562
563
564 class PARTICLE_PT_boidbrain(ParticleButtonsPanel, bpy.types.Panel):
565     bl_label = "Boid Brain"
566     COMPAT_ENGINES = {'BLENDER_RENDER'}
567
568     @classmethod
569     def poll(cls, context):
570         psys = context.particle_system
571         engine = context.scene.render.engine
572         if psys is None:
573             return False
574         if psys.settings is None:
575             return False
576         if psys.point_cache.use_external:
577             return False
578         return psys.settings.physics_type == 'BOIDS' and engine in cls.COMPAT_ENGINES
579
580     def draw(self, context):
581         layout = self.layout
582
583         boids = context.particle_system.settings.boids
584
585         layout.enabled = particle_panel_enabled(context, context.particle_system)
586
587         # Currently boids can only use the first state so these are commented out for now.
588         #row = layout.row()
589         #row.template_list(boids, "states", boids, "active_boid_state_index", compact="True")
590         #col = row.row()
591         #sub = col.row(align=True)
592         #sub.operator("boid.state_add", icon='ZOOMIN', text="")
593         #sub.operator("boid.state_del", icon='ZOOMOUT', text="")
594         #sub = row.row(align=True)
595         #sub.operator("boid.state_move_up", icon='MOVE_UP_VEC', text="")
596         #sub.operator("boid.state_move_down", icon='MOVE_DOWN_VEC', text="")
597
598         state = boids.active_boid_state
599
600         #layout.prop(state, "name", text="State name")
601
602         row = layout.row()
603         row.prop(state, "ruleset_type")
604         if state.ruleset_type == 'FUZZY':
605             row.prop(state, "rule_fuzzy", slider=True)
606         else:
607             row.label(text="")
608
609         row = layout.row()
610         row.template_list(state, "rules", state, "active_boid_rule_index")
611
612         col = row.column()
613         sub = col.row()
614         subsub = sub.column(align=True)
615         subsub.operator_menu_enum("boid.rule_add", "type", icon='ZOOMIN', text="")
616         subsub.operator("boid.rule_del", icon='ZOOMOUT', text="")
617         sub = col.row()
618         subsub = sub.column(align=True)
619         subsub.operator("boid.rule_move_up", icon='MOVE_UP_VEC', text="")
620         subsub.operator("boid.rule_move_down", icon='MOVE_DOWN_VEC', text="")
621
622         rule = state.active_boid_rule
623
624         if rule:
625             row = layout.row()
626             row.prop(rule, "name", text="")
627             #somebody make nice icons for boids here please! -jahka
628             row.prop(rule, "use_in_air", icon='MOVE_UP_VEC', text="")
629             row.prop(rule, "use_on_land", icon='MOVE_DOWN_VEC', text="")
630
631             row = layout.row()
632
633             if rule.type == 'GOAL':
634                 row.prop(rule, "object")
635                 row = layout.row()
636                 row.prop(rule, "use_predict")
637             elif rule.type == 'AVOID':
638                 row.prop(rule, "object")
639                 row = layout.row()
640                 row.prop(rule, "use_predict")
641                 row.prop(rule, "fear_factor")
642             elif rule.type == 'FOLLOW_PATH':
643                 row.label(text="Not yet functional.")
644             elif rule.type == 'AVOID_COLLISION':
645                 row.prop(rule, "use_avoid")
646                 row.prop(rule, "use_avoid_collision")
647                 row.prop(rule, "look_ahead")
648             elif rule.type == 'FOLLOW_LEADER':
649                 row.prop(rule, "object", text="")
650                 row.prop(rule, "distance")
651                 row = layout.row()
652                 row.prop(rule, "use_line")
653                 sub = row.row()
654                 sub.active = rule.line
655                 sub.prop(rule, "queue_count")
656             elif rule.type == 'AVERAGE_SPEED':
657                 row.prop(rule, "speed", slider=True)
658                 row.prop(rule, "wander", slider=True)
659                 row.prop(rule, "level", slider=True)
660             elif rule.type == 'FIGHT':
661                 row.prop(rule, "distance")
662                 row.prop(rule, "flee_distance")
663
664
665 class PARTICLE_PT_render(ParticleButtonsPanel, bpy.types.Panel):
666     bl_label = "Render"
667     COMPAT_ENGINES = {'BLENDER_RENDER'}
668
669     @classmethod
670     def poll(cls, context):
671         psys = context.particle_system
672         engine = context.scene.render.engine
673         if psys is None:
674             return False
675         if psys.settings is None:
676             return False
677         return engine in cls.COMPAT_ENGINES
678
679     def draw(self, context):
680         layout = self.layout
681
682         psys = context.particle_system
683         part = psys.settings
684
685         row = layout.row()
686         row.prop(part, "material")
687         row.prop(psys, "parent")
688
689         split = layout.split()
690
691         sub = split.column()
692         sub.prop(part, "emitter")
693         sub.prop(part, "parent")
694         sub = split.column()
695         sub.prop(part, "show_unborn")
696         sub.prop(part, "use_dead")
697
698         row = layout.row()
699         row.prop(part, "render_type", expand=True)
700
701         split = layout.split()
702
703         sub = split.column()
704
705         if part.render_type == 'LINE':
706             sub.prop(part, "line_length_tail")
707             sub.prop(part, "line_length_head")
708             sub = split.column()
709             sub.prop(part, "use_velocity_length")
710         elif part.render_type == 'PATH':
711             sub.prop(part, "use_strand_primitive")
712             subsub = sub.column()
713             subsub.active = (part.use_strand_primitive is False)
714             subsub.prop(part, "use_render_adaptive")
715             subsub = sub.column()
716             subsub.active = part.render_adaptive or part.use_strand_primitive == True
717             subsub.prop(part, "adaptive_angle")
718             subsub = sub.column()
719             subsub.active = (part.render_adaptive is True and part.use_strand_primitive is False)
720             subsub.prop(part, "adaptive_pixel")
721             sub.prop(part, "use_hair_bspline")
722             sub.prop(part, "render_step", text="Steps")
723
724             sub = split.column()
725             sub.label(text="Timing:")
726             sub.prop(part, "use_absolute_path_time")
727             sub.prop(part, "path_start", text="Start", slider=not part.use_absolute_path_time)
728             sub.prop(part, "path_end", text="End", slider=not part.use_absolute_path_time)
729             sub.prop(part, "length_random", text="Random", slider=True)
730
731             row = layout.row()
732             col = row.column()
733
734             if part.type == 'HAIR' and part.use_strand_primitive == True and part.child_type == 'FACES':
735                 layout.prop(part, "use_simplify")
736                 if part.use_simplify == True:
737                     row = layout.row()
738                     row.prop(part, "simplify_refsize")
739                     row.prop(part, "simplify_rate")
740                     row.prop(part, "simplify_transition")
741                     row = layout.row()
742                     row.prop(part, "viewport")
743                     sub = row.row()
744                     sub.active = part.viewport == True
745                     sub.prop(part, "simplify_viewport")
746
747         elif part.render_type == 'OBJECT':
748             sub.prop(part, "dupli_object")
749             sub.prop(part, "use_global_dupli")
750         elif part.render_type == 'GROUP':
751             sub.prop(part, "dupli_group")
752             split = layout.split()
753             sub = split.column()
754             sub.prop(part, "use_whole_group")
755             subsub = sub.column()
756             subsub.active = (part.use_whole_group is False)
757             subsub.prop(part, "use_group_count")
758
759             sub = split.column()
760             subsub = sub.column()
761             subsub.active = (part.use_whole_group is False)
762             subsub.prop(part, "use_global_dupli")
763             subsub.prop(part, "use_group_pick_random")
764
765             if part.use_group_count and not part.use_whole_group:
766                 row = layout.row()
767                 row.template_list(part, "dupli_weights", part, "active_dupliweight_index")
768
769                 col = row.column()
770                 sub = col.row()
771                 subsub = sub.column(align=True)
772                 subsub.operator("particle.dupliob_copy", icon='ZOOMIN', text="")
773                 subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="")
774                 subsub.operator("particle.dupliob_move_up", icon='MOVE_UP_VEC', text="")
775                 subsub.operator("particle.dupliob_move_down", icon='MOVE_DOWN_VEC', text="")
776
777                 weight = part.active_dupliweight
778                 if weight:
779                     row = layout.row()
780                     row.prop(weight, "count")
781
782         elif part.render_type == 'BILLBOARD':
783             sub.label(text="Align:")
784
785             row = layout.row()
786             row.prop(part, "billboard_align", expand=True)
787             row.prop(part, "lock_billboard", text="Lock")
788             row = layout.row()
789             row.prop(part, "billboard_object")
790
791             row = layout.row()
792             col = row.column(align=True)
793             col.label(text="Tilt:")
794             col.prop(part, "billboard_tilt", text="Angle", slider=True)
795             col.prop(part, "billboard_tilt_random", slider=True)
796             col = row.column()
797             col.prop(part, "billboard_offset")
798
799             row = layout.row()
800             row.prop(psys, "billboard_normal_uv")
801             row = layout.row()
802             row.prop(psys, "billboard_time_index_uv")
803
804             row = layout.row()
805             row.label(text="Split uv's:")
806             row.prop(part, "billboard_uv_split", text="Number of splits")
807             row = layout.row()
808             row.prop(psys, "billboard_split_uv")
809             row = layout.row()
810             row.label(text="Animate:")
811             row.prop(part, "billboard_animation", text="")
812             row.label(text="Offset:")
813             row.prop(part, "billboard_offset_split", text="")
814
815         if part.render_type == 'HALO' or part.render_type == 'LINE' or part.render_type == 'BILLBOARD':
816             row = layout.row()
817             col = row.column()
818             col.prop(part, "trail_count")
819             if part.trail_count > 1:
820                 col.prop(part, "use_absolute_path_time", text="Length in frames")
821                 col = row.column()
822                 col.prop(part, "path_end", text="Length", slider=not part.use_absolute_path_time)
823                 col.prop(part, "length_random", text="Random", slider=True)
824             else:
825                 col = row.column()
826                 col.label(text="")
827
828
829 class PARTICLE_PT_draw(ParticleButtonsPanel, bpy.types.Panel):
830     bl_label = "Display"
831     bl_default_closed = True
832     COMPAT_ENGINES = {'BLENDER_RENDER'}
833
834     @classmethod
835     def poll(cls, context):
836         psys = context.particle_system
837         engine = context.scene.render.engine
838         if psys is None:
839             return False
840         if psys.settings is None:
841             return False
842         return engine in cls.COMPAT_ENGINES
843
844     def draw(self, context):
845         layout = self.layout
846
847         psys = context.particle_system
848         part = psys.settings
849
850         row = layout.row()
851         row.prop(part, "draw_method", expand=True)
852
853         if part.draw_method == 'NONE' or (part.render_type == 'NONE' and part.draw_method == 'RENDER'):
854             return
855
856         path = (part.render_type == 'PATH' and part.draw_method == 'RENDER') or part.draw_method == 'PATH'
857
858         row = layout.row()
859         row.prop(part, "display", slider=True)
860         if part.draw_method != 'RENDER' or part.render_type == 'HALO':
861             row.prop(part, "draw_size")
862         else:
863             row.label(text="")
864
865         row = layout.row()
866         col = row.column()
867         col.prop(part, "show_size")
868         col.prop(part, "velocity")
869         col.prop(part, "show_number")
870         if part.physics_type == 'BOIDS':
871             col.prop(part, "show_health")
872
873         col = row.column()
874         col.prop(part, "show_material_color", text="Use material color")
875
876         if (path):
877             col.prop(part, "draw_step")
878         else:
879             sub = col.column()
880             sub.active = (part.show_material_color is False)
881             #sub.label(text="color")
882             #sub.label(text="Override material color")
883
884
885 class PARTICLE_PT_children(ParticleButtonsPanel, bpy.types.Panel):
886     bl_label = "Children"
887     bl_default_closed = True
888     COMPAT_ENGINES = {'BLENDER_RENDER'}
889
890     @classmethod
891     def poll(cls, context):
892         return particle_panel_poll(cls, context)
893
894     def draw(self, context):
895         layout = self.layout
896
897         psys = context.particle_system
898         part = psys.settings
899
900         layout.row().prop(part, "child_type", expand=True)
901
902         if part.child_type == 'NONE':
903             return
904
905         row = layout.row()
906
907         col = row.column(align=True)
908         col.prop(part, "child_nbr", text="Display")
909         col.prop(part, "rendered_child_count", text="Render")
910
911         col = row.column(align=True)
912
913         if part.child_type == 'FACES':
914             col.prop(part, "virtual_parents", slider=True)
915         else:
916             col.prop(part, "child_radius", text="Radius")
917             col.prop(part, "child_roundness", text="Roundness", slider=True)
918
919             col = row.column(align=True)
920             col.prop(part, "child_size", text="Size")
921             col.prop(part, "child_size_random", text="Random")
922
923         layout.row().label(text="Effects:")
924
925         row = layout.row()
926
927         col = row.column(align=True)
928         col.prop(part, "clump_factor", slider=True)
929         col.prop(part, "clump_shape", slider=True)
930
931         col = row.column(align=True)
932         col.prop(part, "roughness_endpoint")
933         col.prop(part, "roughness_end_shape")
934
935         row = layout.row()
936
937         col = row.column(align=True)
938         col.prop(part, "roughness_1")
939         col.prop(part, "roughness_1_size")
940
941         col = row.column(align=True)
942         col.prop(part, "roughness_2")
943         col.prop(part, "roughness_2_size")
944         col.prop(part, "roughness_2_threshold", slider=True)
945
946         row = layout.row()
947         col = row.column(align=True)
948         col.prop(part, "child_length", slider=True)
949         col.prop(part, "child_length_threshold", slider=True)
950
951         col = row.column(align=True)
952         col.label(text="Space reserved for")
953         col.label(text="hair parting controls")
954
955         layout.row().label(text="Kink:")
956         layout.row().prop(part, "kink", expand=True)
957
958         split = layout.split()
959
960         col = split.column()
961         col.prop(part, "kink_amplitude")
962         col.prop(part, "kink_frequency")
963         col = split.column()
964         col.prop(part, "kink_shape", slider=True)
965
966
967 class PARTICLE_PT_field_weights(ParticleButtonsPanel, bpy.types.Panel):
968     bl_label = "Field Weights"
969     bl_default_closed = True
970     COMPAT_ENGINES = {'BLENDER_RENDER'}
971
972     def draw(self, context):
973         part = context.particle_system.settings
974         effector_weights_ui(self, context, part.effector_weights)
975
976         if part.type == 'HAIR':
977             self.layout.prop(part.effector_weights, "apply_to_hair_growing")
978
979
980 class PARTICLE_PT_force_fields(ParticleButtonsPanel, bpy.types.Panel):
981     bl_label = "Force Field Settings"
982     bl_default_closed = True
983     COMPAT_ENGINES = {'BLENDER_RENDER'}
984
985     def draw(self, context):
986         layout = self.layout
987
988         part = context.particle_system.settings
989
990         layout.prop(part, "use_self_effect")
991
992         split = layout.split(percentage=0.2)
993         split.label(text="Type 1:")
994         split.prop(part.force_field_1, "type", text="")
995         basic_force_field_settings_ui(self, context, part.force_field_1)
996         basic_force_field_falloff_ui(self, context, part.force_field_1)
997
998         if part.force_field_1.type != 'NONE':
999             layout.label(text="")
1000
1001         split = layout.split(percentage=0.2)
1002         split.label(text="Type 2:")
1003         split.prop(part.force_field_2, "type", text="")
1004         basic_force_field_settings_ui(self, context, part.force_field_2)
1005         basic_force_field_falloff_ui(self, context, part.force_field_2)
1006
1007
1008 class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, bpy.types.Panel):
1009     bl_label = "Vertexgroups"
1010     bl_default_closed = True
1011     COMPAT_ENGINES = {'BLENDER_RENDER'}
1012
1013     def draw(self, context):
1014         layout = self.layout
1015
1016         ob = context.object
1017         psys = context.particle_system
1018         # part = psys.settings
1019
1020         # layout.label(text="Nothing here yet.")
1021
1022         row = layout.row()
1023         row.label(text="Vertex Group")
1024         row.label(text="Negate")
1025
1026
1027         row = layout.row()
1028         row.prop_object(psys, "vertex_group_density", ob, "vertex_groups", text="Density")
1029         row.prop(psys, "invert_vertex_group_density", text="")
1030
1031         row = layout.row()
1032         row.prop_object(psys, "vertex_group_velocity", ob, "vertex_groups", text="Velocity")
1033         row.prop(psys, "invert_vertex_group_velocity", text="")
1034
1035         row = layout.row()
1036         row.prop_object(psys, "vertex_group_length", ob, "vertex_groups", text="Length")
1037         row.prop(psys, "invert_vertex_group_length", text="")
1038
1039         row = layout.row()
1040         row.prop_object(psys, "vertex_group_clump", ob, "vertex_groups", text="Clump")
1041         row.prop(psys, "invert_vertex_group_clump", text="")
1042
1043         row = layout.row()
1044         row.prop_object(psys, "vertex_group_kink", ob, "vertex_groups", text="Kink")
1045         row.prop(psys, "invert_vertex_group_kink", text="")
1046
1047         row = layout.row()
1048         row.prop_object(psys, "vertex_group_roughness_1", ob, "vertex_groups", text="Roughness 1")
1049         row.prop(psys, "invert_vertex_group_roughness_1", text="")
1050
1051         row = layout.row()
1052         row.prop_object(psys, "vertex_group_roughness_2", ob, "vertex_groups", text="Roughness 2")
1053         row.prop(psys, "invert_vertex_group_roughness_2", text="")
1054
1055         row = layout.row()
1056         row.prop_object(psys, "vertex_group_roughness_end", ob, "vertex_groups", text="Roughness End")
1057         row.prop(psys, "invert_vertex_group_roughness_end", text="")
1058
1059         row = layout.row()
1060         row.prop_object(psys, "vertex_group_size", ob, "vertex_groups", text="Size")
1061         row.prop(psys, "invert_vertex_group_size", text="")
1062
1063         row = layout.row()
1064         row.prop_object(psys, "vertex_group_tangent", ob, "vertex_groups", text="Tangent")
1065         row.prop(psys, "invert_vertex_group_tangent", text="")
1066
1067         row = layout.row()
1068         row.prop_object(psys, "vertex_group_rotation", ob, "vertex_groups", text="Rotation")
1069         row.prop(psys, "invert_vertex_group_rotation", text="")
1070
1071         row = layout.row()
1072         row.prop_object(psys, "vertex_group_field", ob, "vertex_groups", text="Field")
1073         row.prop(psys, "invert_vertex_group_field", text="")
1074
1075
1076 class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel, bpy.types.Panel):
1077     COMPAT_ENGINES = {'BLENDER_RENDER'}
1078     _context_path = "particle_system.settings"
1079
1080
1081 def register():
1082     pass
1083
1084
1085 def unregister():
1086     pass
1087
1088 if __name__ == "__main__":
1089     register()