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