b102f1b09d053f33f6d4581075b6155229ddce00
[blender.git] / release / scripts / startup / bl_ui / properties_physics_dynamicpaint.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 bpy.types import Panel, UIList
22
23 from bl_ui.properties_physics_common import (point_cache_ui,
24                                              effector_weights_ui,
25                                              )
26
27
28 class PHYSICS_UL_dynapaint_surfaces(UIList):
29     def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
30         if not isinstance(item, bpy.types.DynamicPaintSurface):
31             return
32         surf = item
33         sticon = layout.enum_item_icon(surf, "surface_type", surf.surface_type)
34         if self.layout_type in {'DEFAULT', 'COMPACT'}:
35             row = layout.row(align=True)
36             row.label(text="", icon_value=icon)
37             row.label(text=surf.name, icon_value=sticon)
38             row = layout.row(align=True)
39             if surf.use_color_preview:
40                 row.prop(surf, "show_preview", text="", emboss=False,
41                          icon='RESTRICT_VIEW_OFF' if surf.show_preview else 'RESTRICT_VIEW_ON')
42             row.prop(surf, "is_active", text="")
43         elif self.layout_type in {'GRID'}:
44             layout.alignment = 'CENTER'
45             row = layout.row(align=True)
46             row.label(text="", icon_value=icon)
47             row.label(text="", icon_value=sticon)
48
49
50 class PhysicButtonsPanel():
51     bl_space_type = 'PROPERTIES'
52     bl_region_type = 'WINDOW'
53     bl_context = "physics"
54
55     @classmethod
56     def poll(cls, context):
57         ob = context.object
58         rd = context.scene.render
59         return (ob and ob.type == 'MESH') and (not rd.use_game_engine) and context.dynamic_paint
60
61
62 class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel):
63     bl_label = "Dynamic Paint"
64
65     def draw(self, context):
66         layout = self.layout
67
68         md = context.dynamic_paint
69
70         layout.prop(md, "ui_type", expand=True)
71
72         if md.ui_type == 'CANVAS':
73             canvas = md.canvas_settings
74
75             if canvas is None:
76                 layout.operator("dpaint.type_toggle", text="Add Canvas").type = 'CANVAS'
77             else:
78                 layout.operator("dpaint.type_toggle", text="Remove Canvas", icon='X').type = 'CANVAS'
79
80                 surface = canvas.canvas_surfaces.active
81
82                 row = layout.row()
83                 row.template_list("PHYSICS_UL_dynapaint_surfaces", "", canvas, "canvas_surfaces",
84                                    canvas.canvas_surfaces, "active_index", rows=2)
85
86                 col = row.column(align=True)
87                 col.operator("dpaint.surface_slot_add", icon='ZOOMIN', text="")
88                 col.operator("dpaint.surface_slot_remove", icon='ZOOMOUT', text="")
89
90                 if surface:
91                     layout.prop(surface, "name")
92                     layout.prop(surface, "surface_format")
93
94                     col = layout.column()
95                     if surface.surface_format != 'VERTEX':
96                         col.label(text="Quality:")
97                         col.prop(surface, "image_resolution")
98                     col.prop(surface, "use_antialiasing")
99
100                     col = layout.column()
101                     col.label(text="Frames:")
102                     split = col.split()
103
104                     col = split.column(align=True)
105                     col.prop(surface, "frame_start", text="Start")
106                     col.prop(surface, "frame_end", text="End")
107
108                     split.prop(surface, "frame_substeps")
109
110         elif md.ui_type == 'BRUSH':
111             brush = md.brush_settings
112             engine = context.scene.render.engine
113
114             if brush is None:
115                 layout.operator("dpaint.type_toggle", text="Add Brush").type = 'BRUSH'
116             else:
117                 layout.operator("dpaint.type_toggle", text="Remove Brush", icon='X').type = 'BRUSH'
118
119                 split = layout.split()
120
121                 col = split.column()
122                 col.prop(brush, "use_absolute_alpha")
123                 col.prop(brush, "use_paint_erase")
124                 col.prop(brush, "paint_wetness", text="Wetness")
125
126                 col = split.column()
127                 if engine == 'BLENDER_RENDER':
128                     sub = col.column()
129                     sub.active = (brush.paint_source != 'PARTICLE_SYSTEM')
130                     sub.prop(brush, "use_material")
131                 if brush.use_material and brush.paint_source != 'PARTICLE_SYSTEM' and engine == 'BLENDER_RENDER':
132                     col.prop(brush, "material", text="")
133                     col.prop(brush, "paint_alpha", text="Alpha Factor")
134                 else:
135                     col.prop(brush, "paint_color", text="")
136                     col.prop(brush, "paint_alpha", text="Alpha")
137
138
139 class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel):
140     bl_label = "Dynamic Paint Advanced"
141
142     @classmethod
143     def poll(cls, context):
144         md = context.dynamic_paint
145         rd = context.scene.render
146         return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and (not rd.use_game_engine)
147
148     def draw(self, context):
149         layout = self.layout
150
151         canvas = context.dynamic_paint.canvas_settings
152         surface = canvas.canvas_surfaces.active
153
154         surface_type = surface.surface_type
155
156         layout.prop(surface, "surface_type")
157         layout.separator()
158
159         # dissolve
160         if surface_type == 'PAINT':
161             split = layout.split(percentage=0.35)
162             split.prop(surface, "use_drying", text="Dry:")
163
164             col = split.column()
165             col.active = surface.use_drying
166             split = col.split(percentage=0.7)
167             col = split.column(align=True)
168             col.prop(surface, "dry_speed", text="Time")
169             col.prop(surface, "color_dry_threshold")
170             split.prop(surface, "use_dry_log", text="Slow")
171
172         if surface_type != 'WAVE':
173             split = layout.split(percentage=0.35)
174             col = split.column()
175             if surface_type == 'WEIGHT':
176                 col.prop(surface, "use_dissolve", text="Fade:")
177             else:
178                 col.prop(surface, "use_dissolve", text="Dissolve:")
179             col = split.column()
180             col.active = surface.use_dissolve
181             split = col.split(percentage=0.7)
182             split.prop(surface, "dissolve_speed", text="Time")
183             split.prop(surface, "use_dissolve_log", text="Slow")
184
185         # per type settings
186         if surface_type == 'DISPLACE':
187             layout.prop(surface, "use_incremental_displace")
188             if surface.surface_format == 'VERTEX':
189                 row = layout.row()
190                 row.prop(surface, "depth_clamp")
191                 row.prop(surface, "displace_factor")
192
193         elif surface_type == 'WAVE':
194             layout.prop(surface, "use_wave_open_border")
195
196             split = layout.split()
197
198             col = split.column(align=True)
199             col.prop(surface, "wave_timescale")
200             col.prop(surface, "wave_speed")
201
202             col = split.column(align=True)
203             col.prop(surface, "wave_damping")
204             col.prop(surface, "wave_spring")
205
206         layout.separator()
207         layout.prop(surface, "brush_group")
208         row = layout.row()
209         row.prop(surface, "brush_influence_scale")
210         row.prop(surface, "brush_radius_scale")
211
212
213 class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel):
214     bl_label = "Dynamic Paint Output"
215     bl_options = {'DEFAULT_CLOSED'}
216
217     @classmethod
218     def poll(cls, context):
219         md = context.dynamic_paint
220         rd = context.scene.render
221         if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
222             return 0
223         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
224         return (surface and
225                 (not (surface.surface_format == 'VERTEX' and (surface.surface_type in {'DISPLACE', 'WAVE'}))) and
226                 (not rd.use_game_engine))
227
228     def draw(self, context):
229         layout = self.layout
230
231         canvas = context.dynamic_paint.canvas_settings
232         surface = canvas.canvas_surfaces.active
233         ob = context.object
234
235         surface_type = surface.surface_type
236
237         # vertex format outputs
238         if surface.surface_format == 'VERTEX':
239             if surface_type == 'PAINT':
240                  # toggle active preview
241                 layout.prop(surface, "preview_id")
242
243                 # paint-map output
244                 row = layout.row()
245                 row.prop_search(surface, "output_name_a", ob.data, "vertex_colors", text="Paintmap layer:")
246                 if surface.output_exists(object=ob, index=0):
247                     ic = 'ZOOMOUT'
248                 else:
249                     ic = 'ZOOMIN'
250
251                 row.operator("dpaint.output_toggle", icon=ic, text="").output = 'A'
252
253                 # wet-map output
254                 row = layout.row()
255                 row.prop_search(surface, "output_name_b", ob.data, "vertex_colors", text="Wetmap layer:")
256                 if surface.output_exists(object=ob, index=1):
257                     ic = 'ZOOMOUT'
258                 else:
259                     ic = 'ZOOMIN'
260
261                 row.operator("dpaint.output_toggle", icon=ic, text="").output = 'B'
262
263             elif surface_type == 'WEIGHT':
264                 row = layout.row()
265                 row.prop_search(surface, "output_name_a", ob, "vertex_groups", text="Vertex Group:")
266                 if surface.output_exists(object=ob, index=0):
267                     ic = 'ZOOMOUT'
268                 else:
269                     ic = 'ZOOMIN'
270
271                 row.operator("dpaint.output_toggle", icon=ic, text="").output = 'A'
272
273         # image format outputs
274         if surface.surface_format == 'IMAGE':
275             layout.operator("dpaint.bake", text="Bake Image Sequence", icon='MOD_DYNAMICPAINT')
276             layout.prop_search(surface, "uv_layer", ob.data, "uv_textures", text="UV Map:")
277             layout.separator()
278
279             layout.prop(surface, "image_output_path", text="")
280             row = layout.row()
281             row.prop(surface, "image_fileformat", text="")
282             row.prop(surface, "use_premultiply", text="Premultiply alpha")
283
284             if surface_type == 'PAINT':
285                 split = layout.split(percentage=0.4)
286                 split.prop(surface, "use_output_a", text="Paintmaps:")
287                 sub = split.row()
288                 sub.active = surface.use_output_a
289                 sub.prop(surface, "output_name_a", text="")
290
291                 split = layout.split(percentage=0.4)
292                 split.prop(surface, "use_output_b", text="Wetmaps:")
293                 sub = split.row()
294                 sub.active = surface.use_output_b
295                 sub.prop(surface, "output_name_b", text="")
296             else:
297                 col = layout.column()
298                 col.prop(surface, "output_name_a", text="Filename:")
299                 if surface_type == 'DISPLACE':
300                     col.prop(surface, "displace_type", text="Displace Type")
301                     col.prop(surface, "depth_clamp")
302                 elif surface_type == 'WAVE':
303                     col.prop(surface, "depth_clamp", text="Wave Clamp")
304
305
306 class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel):
307     bl_label = "Dynamic Paint Initial Color"
308     bl_options = {'DEFAULT_CLOSED'}
309
310     @classmethod
311     def poll(cls, context):
312         md = context.dynamic_paint
313         rd = context.scene.render
314         if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
315             return 0
316         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
317         return (surface and surface.surface_type == 'PAINT') and (not rd.use_game_engine)
318
319     def draw(self, context):
320         layout = self.layout
321
322         canvas = context.dynamic_paint.canvas_settings
323         surface = canvas.canvas_surfaces.active
324         ob = context.object
325
326         layout.prop(surface, "init_color_type", expand=False)
327         layout.separator()
328
329         # dissolve
330         if surface.init_color_type == 'COLOR':
331             layout.prop(surface, "init_color")
332
333         elif surface.init_color_type == 'TEXTURE':
334             layout.prop(surface, "init_texture")
335             layout.prop_search(surface, "init_layername", ob.data, "uv_textures", text="UV Map:")
336
337         elif surface.init_color_type == 'VERTEX_COLOR':
338             layout.prop_search(surface, "init_layername", ob.data, "vertex_colors", text="Color Layer:")
339
340
341 class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel):
342     bl_label = "Dynamic Paint Effects"
343     bl_options = {'DEFAULT_CLOSED'}
344
345     @classmethod
346     def poll(cls, context):
347         md = context.dynamic_paint
348         rd = context.scene.render
349         if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
350             return False
351         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
352         return (surface and surface.surface_type == 'PAINT') and (not rd.use_game_engine)
353
354     def draw(self, context):
355         layout = self.layout
356
357         canvas = context.dynamic_paint.canvas_settings
358         surface = canvas.canvas_surfaces.active
359
360         layout.prop(surface, "effect_ui", expand=True)
361
362         if surface.effect_ui == 'SPREAD':
363             layout.prop(surface, "use_spread")
364
365             row = layout.row()
366             row.active = surface.use_spread
367             row.prop(surface, "spread_speed")
368             row.prop(surface, "color_spread_speed")
369
370         elif surface.effect_ui == 'DRIP':
371             layout.prop(surface, "use_drip")
372
373             col = layout.column()
374             col.active = surface.use_drip
375             effector_weights_ui(self, context, surface.effector_weights, 'DYNAMIC_PAINT')
376
377             layout.label(text="Surface Movement:")
378             row = layout.row()
379             row.prop(surface, "drip_velocity", slider=True)
380             row.prop(surface, "drip_acceleration", slider=True)
381
382         elif surface.effect_ui == 'SHRINK':
383             layout.prop(surface, "use_shrink")
384
385             row = layout.row()
386             row.active = surface.use_shrink
387             row.prop(surface, "shrink_speed")
388
389
390 class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel):
391     bl_label = "Dynamic Paint Cache"
392     bl_options = {'DEFAULT_CLOSED'}
393
394     @classmethod
395     def poll(cls, context):
396         md = context.dynamic_paint
397         rd = context.scene.render
398         return (md and
399                 md.ui_type == 'CANVAS' and
400                 md.canvas_settings and
401                 md.canvas_settings.canvas_surfaces.active and
402                 md.canvas_settings.canvas_surfaces.active.is_cache_user and
403                 (not rd.use_game_engine))
404
405     def draw(self, context):
406         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
407         cache = surface.point_cache
408
409         point_cache_ui(self, context, cache, (cache.is_baked is False), 'DYNAMIC_PAINT')
410
411
412 class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel):
413     bl_label = "Dynamic Paint Source"
414
415     @classmethod
416     def poll(cls, context):
417         md = context.dynamic_paint
418         rd = context.scene.render
419         return md and md.ui_type == 'BRUSH' and md.brush_settings and (not rd.use_game_engine)
420
421     def draw(self, context):
422         layout = self.layout
423
424         brush = context.dynamic_paint.brush_settings
425         ob = context.object
426
427         split = layout.split()
428         col = split.column()
429         col.prop(brush, "paint_source")
430
431         if brush.paint_source == 'PARTICLE_SYSTEM':
432             col.prop_search(brush, "particle_system", ob, "particle_systems", text="")
433             if brush.particle_system:
434                 col.label(text="Particle effect:")
435                 sub = col.column()
436                 sub.active = not brush.use_particle_radius
437                 sub.prop(brush, "solid_radius", text="Solid Radius")
438                 col.prop(brush, "use_particle_radius", text="Use Particle's Radius")
439                 col.prop(brush, "smooth_radius", text="Smooth radius")
440
441         if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'}:
442             col.prop(brush, "paint_distance", text="Paint Distance")
443             split = layout.row().split(percentage=0.4)
444             sub = split.column()
445             if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE'}:
446                 sub.prop(brush, "use_proximity_project")
447             if brush.paint_source == 'VOLUME_DISTANCE':
448                 sub.prop(brush, "invert_proximity")
449                 sub.prop(brush, "use_negative_volume")
450
451             sub = split.column()
452             if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE'}:
453                 column = sub.column()
454                 column.active = brush.use_proximity_project
455                 column.prop(brush, "ray_direction")
456             sub.prop(brush, "proximity_falloff")
457             if brush.proximity_falloff == 'RAMP':
458                 col = layout.row().column()
459                 col.separator()
460                 col.prop(brush, "use_proximity_ramp_alpha", text="Only Use Alpha")
461                 col.template_color_ramp(brush, "paint_ramp", expand=True)
462
463
464 class PHYSICS_PT_dp_brush_velocity(PhysicButtonsPanel, Panel):
465     bl_label = "Dynamic Paint Velocity"
466     bl_options = {'DEFAULT_CLOSED'}
467
468     @classmethod
469     def poll(cls, context):
470         md = context.dynamic_paint
471         rd = context.scene.render
472         return md and md.ui_type == 'BRUSH' and md.brush_settings and (not rd.use_game_engine)
473
474     def draw(self, context):
475         layout = self.layout
476
477         brush = context.dynamic_paint.brush_settings
478
479         split = layout.split()
480
481         col = split.column()
482         col.prop(brush, "use_velocity_alpha")
483         col.prop(brush, "use_velocity_color")
484
485         split.prop(brush, "use_velocity_depth")
486
487         col = layout.column()
488         col.active = (brush.use_velocity_alpha or brush.use_velocity_color or brush.use_velocity_depth)
489         col.prop(brush, "velocity_max")
490         col.template_color_ramp(brush, "velocity_ramp", expand=True)
491         layout.separator()
492
493         row = layout.row()
494         row.prop(brush, "use_smudge")
495         sub = row.row()
496         sub.active = brush.use_smudge
497         sub.prop(brush, "smudge_strength")
498
499
500 class PHYSICS_PT_dp_brush_wave(PhysicButtonsPanel, Panel):
501     bl_label = "Dynamic Paint Waves"
502     bl_options = {'DEFAULT_CLOSED'}
503
504     @classmethod
505     def poll(cls, context):
506         md = context.dynamic_paint
507         rd = context.scene.render
508         return md and md.ui_type == 'BRUSH' and md.brush_settings and (not rd.use_game_engine)
509
510     def draw(self, context):
511         layout = self.layout
512
513         brush = context.dynamic_paint.brush_settings
514
515         layout.prop(brush, "wave_type")
516         if brush.wave_type != 'REFLECT':
517             row = layout.row()
518             row.prop(brush, "wave_factor")
519             row.prop(brush, "wave_clamp")
520
521
522 def register():
523     bpy.utils.register_module(__name__)
524
525
526 def unregister():
527     bpy.utils.register_module(__name__)
528
529 if __name__ == "__main__":
530     register()