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